def maybeExportToCSV(tdb, cmdenv): if cmdenv.noExport: cmdenv.DEBUG0("no-export set, not exporting stations") return lines, csvPath = csvexport.exportTableToFile(tdb, cmdenv, "ShipVendor") cmdenv.NOTE("{} updated.", csvPath)
def run(results, cmdenv, tdb): # check database exists if not tdb.dbPath.is_file(): raise CommandLineError("Database '{}' not found.".format(tdb.dbPath)) # check export path exists if cmdenv.path: # the "--path" overwrites the default path of TD exportPath = Path(cmdenv.path) else: exportPath = Path(cmdenv.dataDir) if not exportPath.is_dir(): raise CommandLineError("Save location '{}' not found.".format(str(exportPath))) # connect to the database cmdenv.NOTE("Using database '{}'", tdb.dbPath) conn = tdb.getDB() conn.row_factory = sqlite3.Row # some tables might be ignored ignoreList = [] # extract tables from command line if cmdenv.tables: bindValues = cmdenv.tables.split(',') tableStmt = " AND name COLLATE NOCASE IN ({})".format(",".join("?" * len(bindValues))) cmdenv.DEBUG0(tableStmt) else: bindValues = [] tableStmt = '' if not cmdenv.allTables: ignoreList.append("StationItem") tableCursor = conn.cursor() for row in tableCursor.execute(""" SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' {cmdTables} ORDER BY name """.format(cmdTables=tableStmt), bindValues): tableName = row['name'] if tableName in ignoreList: # ignore the table cmdenv.NOTE("Ignore Table '{table}'", table=tableName) continue cmdenv.NOTE("Export Table '{table}'", table=tableName) # create CSV files lineCount, filePath = exportTableToFile(tdb, cmdenv, tableName, exportPath) if cmdenv.deleteEmpty and lineCount == 0: # delete file if emtpy filePath.unlink() cmdenv.DEBUG0("Delete empty file {file}'".format(file=filePath)) return None
def refresh_csv(self): if not self.getOption("exportcsv"): return for table in [ "Category", "Item", "System", "Station", "Ship", "ShipVendor", "RareItem" ]: _, path = csvexport.exportTableToFile(self.tdb, self.tdenv, table) self.tdenv.NOTE("{} re-exported.", path)
def refresh_csv(self): if not self.getOption("exportcsv"): return for table in [ "Category", "Item", "System", "Station", "Ship", "ShipVendor", "RareItem" ]: _, path = csvexport.exportTableToFile( self.tdb, self.tdenv, table ) self.tdenv.NOTE("{} re-exported.", path)
def checkResultAndExportStations(tdb, cmdenv, result): if not result: cmdenv.NOTE("No changes.") return None if cmdenv.noExport: cmdenv.DEBUG0("no-export set, not exporting stations") return None lines, csvPath = csvexport.exportTableToFile(tdb, cmdenv, "Station") cmdenv.NOTE("{} updated.", csvPath) if cmdenv.remove: if cmdenv.stationItemCount: cmdenv.NOTE("Station had items, regenerating .prices file") cache.regeneratePricesFile(tdb, cmdenv) return None
def regenerate(self): for table in [ "Category", "Item", "RareItem", "Ship", "ShipVendor", "Station", "System", "Upgrade", "UpgradeVendor", ]: if self.updated[table]: _, path = csvexport.exportTableToFile( self.tdb, self.tdenv, table ) self.tdenv.NOTE("{} exported.", path)
def process_fdevids_table(self, localPath, tableName): """ Shipyard and outfitting files can be directly imported. """ tdb, tdenv = self.tdb, self.tdenv tdenv.NOTE("Processing {}", tableName) db = tdb.getDB() db.execute("DELETE FROM {}".format(tableName)) cache.processImportFile(tdenv, db, localPath, tableName) db.commit() lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, tableName, ) tdenv.NOTE("Imported {} {}(s).", lines, tableName) tdenv.NOTE("{} updated.", csvPath)
yield tdStn, eddbStn updateStation = tdb.updateLocalStation bool_trans = {None: "?", 0: "N", 1: "Y"} updates = 0 for tdStn, eddbStn in matching_stations(): mps = eddbStn["max_landing_pad_size"] or "?" if updateStation( station=tdStn, lsFromStar=eddbStn["distance_to_star"], maxPadSize=mps, market=bool_trans[eddbStn["has_commodities"]], blackMarket=bool_trans[eddbStn["has_blackmarket"]], shipyard=bool_trans[eddbStn["has_shipyard"]], outfitting=bool_trans[eddbStn["has_outfitting"]], rearm=bool_trans[eddbStn["has_rearm"]], refuel=bool_trans[eddbStn["has_refuel"]], repair=bool_trans[eddbStn["has_repair"]], modified="now", commit=False, ): updates += 1 if updates: tdb.getDB().commit() csvexport.exportTableToFile(tdb, tdb.tdenv, "Station") print("Updated Station.csv: {} updates".format(updates))
def parseLogDirList(self): """ parse netLog files """ # HEADER: 16-07-02-00:18 Mitteleuropäische Sommerzeit (22:18 GMT) - part 1 # SYSTEM: {00:20:24} System:"Caelinus" StarPos:(0.188,-18.625,52.063)ly NormalFlight # or (since 2.3) # HEADER: ============================================ # HEADER: Logs/netLog.170430120645.01.log (part 1) # HEADER: 2017-04-30 12:06 Mitteleuropäische Sommerzeit # HEADER: ============================================ # SYSTEM: {10:13:33GMT 407.863s} System:"Huokang" StarPos:(-12.188,35.469,-25.281)ly NormalFlight tdb, tdenv = self.tdb, self.tdenv optShow = self.getOption("show") oldHeadRegEx = re.compile( "^(?P<headDateTime>\d\d-\d\d-\d\d-\d\d:\d\d)\s+(?P<headTZName>.*[^\s])\s+(?P<headTimeGMT>\(.*GMT\))" ) newHeadRegEx = re.compile( "^(?P<headDateTime>\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)\s+(?P<headTZName>.*[^\s])" ) sysRegEx = re.compile( '^\{[^\}]+\}\s+System:"(?P<sysName>[^"]+)".*StarPos:\((?P<sysPos>[^)]+)\)ly' ) dateRegEx = re.compile('^\{(?P<logTime>\d\d:\d\d:\d\d)') def calcSeconds(h=0, m=0, s=0): return 3600 * h + 60 * m + s sysCount = 0 logSysList = {} for filePath in self.filePathList: tdenv.NOTE("parsing '{}'", filePath.name) oldCount = sysCount with filePath.open() as logFile: headDate, headMatch = None, None lineCount = 0 statHeader = True for line in logFile: lineCount += 1 line = line.strip('\r\n') if statHeader: # parse header line to get the date and timezone tdenv.DEBUG0( " HEADER: {}", line.replace("{", "{{").replace("}", "}}")) if lineCount == 1: # old format headMatch = oldHeadRegEx.match(line) timeFormat = '%y-%m-%d-%H:%M' if lineCount == 3: # new format since 2.3 headMatch = newHeadRegEx.match(line) timeFormat = '%Y-%m-%d %H:%M' if headMatch: headDate = headMatch.group('headDateTime') headTZName = headMatch.group('headTZName') if headTZName == _time.tzname[1]: # daylight saving time headTZInfo = timedelta(seconds=-_time.altzone) else: # normal time headTZInfo = timedelta(seconds=-_time.timezone) tdenv.DEBUG0(" HEADER: Date {}".format(headDate)) tdenv.DEBUG0( " HEADER: TZInfo {}".format(headTZInfo)) try: # convert it into something useable headDate = datetime.fromtimestamp( _time.mktime( _time.strptime(headDate, timeFormat)), timezone(headTZInfo)) except: headDate = None pass if not headDate: if lineCount > 3: raise PluginException( "Doesn't seem do be a FDEV netLog file") else: statHeader = False if lineCount == 3: # new format since 2.3, switch to UTC headDate = headDate.astimezone() tdenv.DEBUG0(" DATE: {}", headDate) headSecs = calcSeconds(headDate.hour, headDate.minute, headDate.second) lastDate = logDate = headDate lastSecs = logSecs = headSecs else: tdenv.DEBUG1( "LOGLINE: {}", line.replace("{", "{{").replace("}", "}}")) # check every line for new time to enhance the lastDate # use time difference because of different timezone usage logTimeMatch = dateRegEx.match(line) if logTimeMatch: h, m, s = logTimeMatch.group('logTime').split(":") logSecs = calcSeconds(int(h), int(m), int(s)) logDiff = logSecs - lastSecs if logDiff < 0: # it's a new day logDiff += 86400 logDate = lastDate + timedelta(seconds=logDiff) tdenv.DEBUG1("LOGDATE: {}", logDate) sysMatch = sysRegEx.match(line) if sysMatch: # we found a system, yeah sysDate = logDate sysName = sysMatch.group('sysName') sysPos = sysMatch.group('sysPos') sysPosX, sysPosY, sysPosZ = sysPos.split(',') sysPosX = snapToGrid32(sysPosX) sysPosY = snapToGrid32(sysPosY) sysPosZ = snapToGrid32(sysPosZ) tdenv.DEBUG0(" SYSTEM: {} {} {} {} {}", sysDate, sysName, sysPosX, sysPosY, sysPosZ) logSysList[sysName] = (sysPosX, sysPosY, sysPosZ, sysDate) lastDate = logDate lastSecs = logSecs sysCount = len(logSysList) tdenv.NOTE("Found {} System(s).", sysCount - oldCount) if not optShow: try: idNetLog = tdb.lookupAdded(self.ADDED_NAME) except KeyError: tdenv.WARN("Entry '{}' not found in 'Added' table.", self.ADDED_NAME) tdenv.WARN("Trying to add it myself.") db = tdb.getDB() cur = db.cursor() cur.execute( """ INSERT INTO Added(name) VALUES(?) """, [self.ADDED_NAME]) db.commit() tdenv.NOTE("Export Table 'Added'") _, path = csvexport.exportTableToFile(tdb, tdenv, "Added") pass addCount = 0 oldCount = 0 newCount = 0 for sysName in logSysList: sysPosX, sysPosY, sysPosZ, sysDate = logSysList[sysName] utcDate = sysDate.astimezone( timezone.utc).strftime('%Y-%m-%d %H:%M:%S') tdenv.DEBUG0("log system '{}' ({}, {}, {}, '{}')", sysName, sysPosX, sysPosY, sysPosZ, utcDate) if sysName.upper() in self.ignoreSysNames: tdenv.NOTE("Ignoring system: '{}'", sysName) continue systemTD = tdb.systemByName.get(sysName.upper(), None) if systemTD: # we allready know the system, check coords tdenv.DEBUG0("Old system '{}' ({}, {}, {})", systemTD.dbname, systemTD.posX, systemTD.posY, systemTD.posZ) oldCount += 1 if not (systemTD.posX == sysPosX and systemTD.posY == sysPosY and systemTD.posZ == sysPosZ): tdenv.WARN("System '{}' has different coordinates:", sysName) tdenv.WARN(" database: {}, {}, {}", systemTD.posX, systemTD.posY, systemTD.posZ) tdenv.WARN(" netlog: {}, {}, {}", sysPosX, sysPosY, sysPosZ) else: # new system tdenv.NOTE("New system '{}' ({}, {}, {}, '{}')", sysName, sysPosX, sysPosY, sysPosZ, utcDate) newCount += 1 if not optShow: tdb.addLocalSystem(sysName.upper(), sysPosX, sysPosY, sysPosZ, added=self.ADDED_NAME, modified=utcDate, commit=False) addCount += 1 tdenv.NOTE("Found {:>3} System(s) altogether.", sysCount) if oldCount: tdenv.NOTE(" {:>3} old", oldCount) if newCount: tdenv.NOTE(" {:>3} new", newCount) if addCount: tdenv.NOTE(" {:>3} added", addCount) tdb.getDB().commit() tdenv.NOTE("Export Table 'System'") _, path = csvexport.exportTableToFile(tdb, tdenv, "System")
def check_edcd_local(self): """ Check EDCD items against local DB """ tdb, tdenv = self.tdb, self.tdenv addItem = 0 updItem = 0 addCategory = 0 commit = False db = tdb.getDB() for catNameEDCD in sorted(self.edcdCategories): catEDCD = self.edcdCategories[catNameEDCD] if catEDCD.dbname not in self.tdCategories: tdenv.NOTE("New category '{}'", catEDCD.dbname) sqlStmt = "INSERT INTO Category(name) VALUES(?)" tdenv.DEBUG0("SQL-Statement: {}", sqlStmt) tdenv.DEBUG0("SQL-Values: {}", [catEDCD.dbname]) db.execute(sqlStmt, [catEDCD.dbname]) addCategory += 1 commit = True # Check EDCD items against local DB for itemEDCD in sorted(catEDCD.items, key=lambda x: x.dbname): itemTD = tdb.itemByName.get(itemEDCD.dbname, None) if not itemTD: itemTD = tdb.itemByFDevID.get(itemEDCD.fdevID, None) if itemTD: tdenv.WARN( "Item '{}' has different name '{}' (TD) != '{} '(EDCD).", itemEDCD.fdevID, itemEDCD.dbname, itemTD.dbname) else: tdenv.NOTE("New Item '{}'", itemEDCD.fullname) insColumns = [ "name", "category_id", "avg_price", "fdev_id" ] insValues = [ itemEDCD.dbname, catEDCD.dbname, itemEDCD.avgPrice, itemEDCD.fdevID ] sqlStmt = ("INSERT INTO Item({}) VALUES(?," "(SELECT category_id " "FROM Category WHERE name = ?),?,?)".format( ",".join(insColumns))) tdenv.DEBUG0("SQL-Statement: {}", sqlStmt) tdenv.DEBUG0("SQL-Values: {}", insValues) db.execute(sqlStmt, insValues) addItem += 1 commit = True else: updValues = list() updColumns = list() if itemEDCD.avgPrice and itemTD.avgPrice != itemEDCD.avgPrice: updColumns.append('avg_price') updValues.append(itemEDCD.avgPrice) if not itemTD.fdevID: updColumns.append('fdev_id') updValues.append(itemEDCD.fdevID) else: if itemTD.fdevID != itemEDCD.fdevID: tdenv.WARN( "Item '{}' has different FDevID {} (TD) != {} (EDCD).", itemTD.fullname, itemTD.fdevID, itemEDCD.fdevID) if len(updColumns): tdenv.NOTE("Update Item '{}' {} {}", itemTD.fullname, updColumns, updValues) updValues.append(itemTD.ID) sqlStmt = ("UPDATE Item SET {} = ?" " WHERE Item.item_id = ?".format( " = ?,".join(updColumns))) tdenv.DEBUG0("SQL-Statement: {}", sqlStmt) tdenv.DEBUG0("SQL-Values: {}", updValues) db.execute(sqlStmt, updValues) updItem += 1 commit = True if addItem: self.update_item_order(db) if commit: db.commit() if addCategory: tdenv.NOTE("Added {} categorie(s)", addCategory) _, csvPath = csvexport.exportTableToFile( tdb, tdenv, 'Category') tdenv.NOTE("{} updated.", csvPath) if addItem or updItem: for textAdd, intAdd in [('Added', addItem), ('Updated', updItem)]: if intAdd: tdenv.NOTE("{} {} item(s)", textAdd, intAdd) _, csvPath = csvexport.exportTableToFile(tdb, tdenv, 'Item') tdenv.NOTE("{} updated.", csvPath) if not commit: tdenv.NOTE("Nothing had to be done")
def run(results, cmdenv, tdb): # check database exists if not tdb.dbPath.is_file(): raise CommandLineError("Database '{}' not found.".format(tdb.dbPath)) # check export path exists if cmdenv.path: # the "--path" overwrites the default path of TD exportPath = Path(cmdenv.path) else: exportPath = Path(cmdenv.dataDir) if not exportPath.is_dir(): raise CommandLineError("Save location '{}' not found.".format( str(exportPath))) # connect to the database cmdenv.NOTE("Using database '{}'", tdb.dbPath) conn = tdb.getDB() conn.row_factory = sqlite3.Row # some tables might be ignored ignoreList = [] # extract tables from command line if cmdenv.tables: bindValues = cmdenv.tables.split(',') tableStmt = " AND name COLLATE NOCASE IN ({})".format(",".join( "?" * len(bindValues))) cmdenv.DEBUG0(tableStmt) else: bindValues = [] tableStmt = '' if not cmdenv.allTables: ignoreList.append("StationItem") tableCursor = conn.cursor() for row in tableCursor.execute( """ SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' {cmdTables} ORDER BY name """.format(cmdTables=tableStmt), bindValues): tableName = row['name'] if tableName in ignoreList: # ignore the table cmdenv.NOTE("Ignore Table '{table}'", table=tableName) continue cmdenv.NOTE("Export Table '{table}'", table=tableName) # create CSV files lineCount, filePath = exportTableToFile(tdb, cmdenv, tableName, exportPath) if cmdenv.deleteEmpty and lineCount == 0: # delete file if emtpy filePath.unlink() cmdenv.DEBUG0("Delete empty file {file}'".format(file=filePath)) return None
def run(self): tdb, tdenv = self.tdb, self.tdenv # first check for EDCD if self.getOption("edcd"): # Call the EDCD plugin try: import plugins.edcd_plug as EDCD except: raise plugins.PluginException("EDCD plugin not found.") tdenv.NOTE("Calling the EDCD plugin.") edcdPlugin = EDCD.ImportPlugin(tdb, tdenv) edcdPlugin.options["csvs"] = True edcdPlugin.run() tdenv.NOTE("Going back to EDAPI.\n") # now load the mapping tables itemMap = mapping.FDEVMappingItems(tdb, tdenv) shipMap = mapping.FDEVMappingShips(tdb, tdenv) # Connect to the API, authenticate, and pull down the commander # /profile. if self.getOption("test"): tdenv.WARN("#############################") tdenv.WARN("### EDAPI in test mode. ###") tdenv.WARN("#############################") apiED = namedtuple('EDAPI', ['profile','text']) try: proPath = pathlib.Path(self.getOption("test")) except TypeError: raise plugins.PluginException( "Option 'test' must be a file name" ) if proPath.exists(): with proPath.open() as proFile: proData = json.load(proFile) if isinstance(proData, list): # since 4.3.0: list(profile, market, shipyard) testProfile = proData[0] for data in proData[1:]: if int(data["id"]) == int(testProfile["lastStarport"]["id"]): testProfile["lastStarport"].update(data) else: testProfile = proData api = apiED( profile = testProfile, text = '{{"mode":"test","file":"{}"}}'.format(str(proPath)) ) else: raise plugins.PluginException( "JSON-file '{}' not found.".format(str(proPath)) ) else: api = EDAPI( cookiefile=str(self.cookiePath), login=self.getOption('login'), debug=tdenv.debug, ) self.edAPI = api # save profile if requested if self.getOption("save"): saveName = 'tmp/profile.' + time.strftime('%Y%m%d_%H%M%S') + '.json' with open(saveName, 'w', encoding="utf-8") as saveFile: if isinstance(api.text, list): # since 4.3.0: list(profile, market, shipyard) saveFile.write("[{}]".format(",".join(api.text))) else: saveFile.write(api.text) print('API response saved to: {}'.format(saveName)) # Sanity check that the commander is docked. Otherwise we will get a # mismatch between the last system and last station. if not api.profile['commander']['docked']: print('Commander not docked. Aborting!') return False # Figure out where we are. sysName = api.profile['lastSystem']['name'] stnName = api.profile['lastStarport']['name'] print('@{}/{}'.format(sysName.upper(), stnName)) # Reload the cache. tdenv.DEBUG0("Checking the cache") tdb.close() tdb.reloadCache() tdb.load( maxSystemLinkLy=tdenv.maxSystemLinkLy, ) tdb.close() # Check to see if this system is in the database try: system = tdb.lookupSystem(sysName) except LookupError: raise plugins.PluginException( "System '{}' unknown.".format(sysName) ) # Check to see if this station is in the database try: station = tdb.lookupStation(stnName, system) except LookupError: station = None # New or update station data station = self.askForStationData(system, stnName=stnName, station=station) # If a shipyard exists, make the ship lists shipCost = {} shipList = [] eddn_ships = [] if ((station.shipyard == "Y") and ('ships' in api.profile['lastStarport']) ): if 'shipyard_list' in api.profile['lastStarport']['ships']: if len(api.profile['lastStarport']['ships']['shipyard_list']): for ship in api.profile['lastStarport']['ships']['shipyard_list'].values(): shipName = shipMap.mapID(ship['id'], ship['name']) shipCost[shipName] = ship['basevalue'] shipList.append(shipName) eddn_ships.append(ship['name']) if 'unavailable_list' in api.profile['lastStarport']['ships']: for ship in api.profile['lastStarport']['ships']['unavailable_list']: shipName = shipMap.mapID(ship['id'], ship['name']) shipCost[shipName] = ship['basevalue'] shipList.append(shipName) eddn_ships.append(ship['name']) if self.getOption("csvs"): addRows = delRows = 0 db = tdb.getDB() if station.shipyard == "N": # delete all ships if there is no shipyard delRows = db.execute( """ DELETE FROM ShipVendor WHERE station_id = ? """, [station.ID] ).rowcount if len(shipList): # and now update the shipyard list # we go through all ships to decide if a ship needs to be # added or deleted from the shipyard for shipID in tdb.shipByID: shipName = tdb.shipByID[shipID].dbname if shipName in shipList: # check for ship discount, costTD = 100% # python builtin round() uses "Round half to even" # but we need commercial rounding, so we do it ourself costTD = tdb.shipByID[shipID].cost costED = int((shipCost[shipName]+5)/10)*10 if costTD != costED: prozED = int(shipCost[shipName]*100/costTD+0.5)-100 tdenv.NOTE( "CostDiff {}: {} != {} ({}%)", shipName, costTD, costED, prozED ) # add the ship to the shipyard shipSQL = ( "INSERT OR IGNORE" " INTO ShipVendor(station_id, ship_id)" " VALUES(?, ?)" ) tdenv.DEBUG0(shipSQL.replace("?", "{}"), station.ID, shipID) addRows += db.execute(shipSQL, [station.ID, shipID]).rowcount else: # delete the ship from the shipyard shipSQL = ( "DELETE FROM ShipVendor" " WHERE station_id = ?" " AND ship_id = ?" ) tdenv.DEBUG0(shipSQL.replace("?", "{}"), station.ID, shipID) delRows += db.execute(shipSQL, [station.ID, shipID]).rowcount db.commit() if (addRows + delRows) > 0: if addRows > 0: tdenv.NOTE( "Added {} ships in '{}' shipyard.", addRows, station.name() ) if delRows > 0: tdenv.NOTE( "Deleted {} ships in '{}' shipyard.", delRows, station.name() ) lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "ShipVendor", ) tdenv.DEBUG0("{} updated.", csvPath) # If a market exists, make the item lists itemList = [] eddn_market = [] if ((station.market == "Y") and ('commodities' in api.profile['lastStarport']) ): for commodity in api.profile['lastStarport']['commodities']: if commodity['categoryname'] in cat_ignore: continue if commodity.get('legality', '') != '': # ignore if present and not empty continue locName = commodity.get('locName', commodity['name']) itmName = itemMap.mapID(commodity['id'], locName) def commodity_int(key): try: ret = int(float(commodity[key])+0.5) except (ValueError, KeyError): ret = 0 return ret itmSupply = commodity_int('stock') itmDemand = commodity_int('demand') itmSupplyLevel = commodity_int('stockBracket') itmDemandLevel = commodity_int('demandBracket') itmBuyPrice = commodity_int('buyPrice') itmSellPrice = commodity_int('sellPrice') if itmSupplyLevel == 0 or itmBuyPrice == 0: # If there is not stockBracket or buyPrice, ignore stock itmBuyPrice = 0 itmSupply = 0 itmSupplyLevel = 0 tdSupply = "-" tdDemand = "{}{}".format( itmDemand, bracket_levels[itmDemandLevel] ) else: # otherwise don't care about demand itmDemand = 0 itmDemandLevel = 0 tdDemand = "?" tdSupply = "{}{}".format( itmSupply, bracket_levels[itmSupplyLevel] ) # ignore items without supply or demand bracket (TD only) if itmSupplyLevel > 0 or itmDemandLevel > 0: itemTD = ( itmName, itmSellPrice, itmBuyPrice, tdDemand, tdSupply, ) itemList.append(itemTD) # Populate EDDN if self.getOption("eddn"): itemEDDN = { "name": commodity['name'], "meanPrice": commodity_int('meanPrice'), "buyPrice": commodity_int('buyPrice'), "stock": commodity_int('stock'), "stockBracket": commodity['stockBracket'], "sellPrice": commodity_int('sellPrice'), "demand": commodity_int('demand'), "demandBracket": commodity['demandBracket'], } if len(commodity['statusFlags']) > 0: itemEDDN["statusFlags"] = commodity['statusFlags'] eddn_market.append(itemEDDN) if itemList: # Create the import file. with open(self.filename, 'w', encoding="utf-8") as f: # write System/Station line f.write("@ {}/{}\n".format(sysName, stnName)) # write Item lines (category lines are not needed) for itemTD in itemList: f.write("\t\t%s %s %s %s %s\n" % itemTD) tdenv.ignoreUnknown = True cache.importDataFromFile( tdb, tdenv, pathlib.Path(self.filename), ) # Import EDDN if self.getOption("eddn"): con = EDDN( api.profile['commander']['name'], self.getOption("name"), 'EDAPI Trade Dangerous Plugin', __version__ ) if self.getOption("test"): con._debug = True else: con._debug = False if eddn_market: print('Posting commodities to EDDN...') con.publishCommodities( sysName, stnName, eddn_market ) if eddn_ships: print('Posting shipyard to EDDN...') con.publishShipyard( sysName, stnName, eddn_ships ) if ((station.outfitting == "Y") and ('modules' in api.profile['lastStarport']) ): eddn_modules = [] for module in api.profile['lastStarport']['modules'].values(): # see: https://github.com/EDSM-NET/EDDN/wiki addModule = False if module['name'].startswith(('Hpt_', 'Int_')) or module['name'].find('_Armour_') > 0: if module.get('sku', None) in ( None, 'ELITE_HORIZONS_V_PLANETARY_LANDINGS' ): if module['name'] != 'Int_PlanetApproachSuite': addModule = True if addModule: eddn_modules.append(module['name']) elif self.getOption("test"): tdenv.NOTE("Ignored module ID: {}, name: {}", module['id'], module['name']) if eddn_modules: print('Posting outfitting to EDDN...') con.publishOutfitting( sysName, stnName, sorted(eddn_modules) ) # We did all the work return False
def askForStationData(self, system, stnName=None, station=None): """ Ask for new or updated station data """ tdb, tdenv = self.tdb, self.tdenv askForData = False stnDefault = namedtuple( 'stnDefault', [ 'lsFromStar','market','blackMarket','shipyard','maxPadSize', 'outfitting','rearm','refuel','repair','planetary', ] ) def tellUserAPIResponse(defName, defValue): if defValue == "Y": tdenv.NOTE("{:>12} in API response", defName) else: tdenv.NOTE("{:>12} NOT in API response", defName) def getYNfromObject(obj, key): return "Y" if key in obj else "N" # defaults from API response are not reliable! checkStarport = self.edAPI.profile['lastStarport'] defMarket = getYNfromObject(checkStarport, 'commodities') defShipyard = getYNfromObject(checkStarport, 'ships') defOutfitting = getYNfromObject(checkStarport, 'modules') tellUserAPIResponse("'Outfitting'", defOutfitting) tellUserAPIResponse("'ShipYard'", defShipyard) tellUserAPIResponse("'Market'", defMarket) def warnAPIResponse(checkName, checkYN): # no warning if unknown if checkYN == "?": return False warnText = ( "The station should{s} have a {what}, " "but the API did{d} return one." ) if checkYN == "Y": s, d = "", "n't" else: s, d = "n't", "" tdenv.WARN(warnText, what=checkName, s=s, d=d) return True if self.getOption('warn') else False # station services since ED update 2.4 checkServices = checkStarport.get('services', None) if checkServices: if station: tdenv.NOTE('Station known.') stnlsFromStar = station.lsFromStar stnmaxPadSize = station.maxPadSize stnplanetary = station.planetary else: tdenv.NOTE('Station unknown.') stnlsFromStar = 0 stnmaxPadSize = "?" stnplanetary = "?" tdenv.NOTE("Found station services.") if checkStarport.get('outpostType', None) == 'starport': # only the big one can be detected stnmaxPadSize = "L" stnplanetary = "N" defStation = stnDefault( lsFromStar = stnlsFromStar, market = getYNfromObject(checkServices, 'commodities'), blackMarket = getYNfromObject(checkServices, 'blackmarket'), shipyard = getYNfromObject(checkServices, 'shipyard'), maxPadSize = stnmaxPadSize, outfitting = getYNfromObject(checkServices, 'outfitting'), rearm = getYNfromObject(checkServices, 'rearm'), refuel = getYNfromObject(checkServices, 'refuel'), repair = getYNfromObject(checkServices, 'repair'), planetary = stnplanetary, ) elif station: tdenv.NOTE('Station known.') defStation = stnDefault( lsFromStar = station.lsFromStar, market = defMarket if station.market == "?" else station.market, blackMarket = station.blackMarket, shipyard = defShipyard if station.shipyard == "?" else station.shipyard, maxPadSize = station.maxPadSize, outfitting = defOutfitting if station.outfitting == "?" else station.outfitting, rearm = station.rearm, refuel = station.refuel, repair = station.repair, planetary = station.planetary, ) else: tdenv.NOTE('Station unknown.') defStation = stnDefault( lsFromStar = 0, market = defMarket, blackMarket = "?", shipyard = defShipyard, maxPadSize = "?", outfitting = defOutfitting, rearm = "?", refuel = "?", repair = "?", planetary = "?", ) warning = False if defStation.outfitting != defOutfitting: warning |= warnAPIResponse('outfitting', defStation.outfitting) if defStation.shipyard != defShipyard: warning |= warnAPIResponse('shipyard', defStation.shipyard) if defStation.market != defMarket: warning |= warnAPIResponse('market', defStation.market) if warning: tdenv.WARN("Please update station data with correct values.") tdenv.WARN("(Fields will be marked with an leading asterisk '*')") askForData = True if ((defStation.lsFromStar == 0) or ("?" in defStation)): askForData = True newStation = {} for key in defStation._fields: newStation[key] = getattr(defStation, key) if askForData: tdenv.NOTE("Values in brackets are the default.") lsFromStar = input( " Stn/Ls..............[{}]: ".format(defStation.lsFromStar) ) or defStation.lsFromStar try: lsFromStar = int(float(lsFromStar)+0.5) except: print("That doesn't seem to be a number. Defaulting to zero.") lsFromStar = defStation.lsFromStar newStation['lsFromStar'] = lsFromStar for askText, askField, markValue in [ ('Pad Size....(s,m,l) ', 'maxPadSize', defStation.maxPadSize), ('Planetary.....(y,n) ', 'planetary', defStation.planetary), ('B/Market......(y,n) ', 'blackMarket', defStation.blackMarket), ('Refuel........(y,n) ', 'refuel', defStation.refuel), ('Repair........(y,n) ', 'repair', defStation.repair), ('Restock.......(y,n) ', 'rearm', defStation.rearm), ('Outfitting....(y,n) ', 'outfitting', defOutfitting), ('Shipyard......(y,n) ', 'shipyard', defShipyard), ('Market........(y,n) ', 'market', defMarket), ]: defValue = getattr(defStation, askField) if defValue != markValue: mark = "*" else: mark = " " askValue = input( "{}{}[{}]: ".format(mark, askText, defValue) ) or defValue newStation[askField] = askValue else: def _detail(value, source): detail = source[value] if detail == '?': detail += ' [unknown]' return detail ls = newStation['lsFromStar'] print(" Stn/Ls....:", ls, '[unknown]' if ls == 0 else '') print(" Pad Size..:", _detail(newStation['maxPadSize'], tdb.padSizes)) print(" Planetary.:", _detail(newStation['planetary'], tdb.planetStates)) print(" B/Market..:", _detail(newStation['blackMarket'], tdb.marketStates)) print(" Refuel....:", _detail(newStation['refuel'], tdb.marketStates)) print(" Repair....:", _detail(newStation['repair'], tdb.marketStates)) print(" Restock...:", _detail(newStation['rearm'], tdb.marketStates)) print(" Outfitting:", _detail(newStation['outfitting'], tdb.marketStates)) print(" Shipyard..:", _detail(newStation['shipyard'], tdb.marketStates)) print(" Market....:", _detail(newStation['market'], tdb.marketStates)) exportCSV = False if not station: station = tdb.addLocalStation( system=system, name=stnName, lsFromStar=newStation['lsFromStar'], blackMarket=newStation['blackMarket'], maxPadSize=newStation['maxPadSize'], market=newStation['market'], shipyard=newStation['shipyard'], outfitting=newStation['outfitting'], rearm=newStation['rearm'], refuel=newStation['refuel'], repair=newStation['repair'], planetary=newStation['planetary'], ) exportCSV = True else: # let the function check for changes if tdb.updateLocalStation( station=station, lsFromStar=newStation['lsFromStar'], blackMarket=newStation['blackMarket'], maxPadSize=newStation['maxPadSize'], market=newStation['market'], shipyard=newStation['shipyard'], outfitting=newStation['outfitting'], rearm=newStation['rearm'], refuel=newStation['refuel'], repair=newStation['repair'], planetary=newStation['planetary'], ): exportCSV = True if exportCSV: lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "Station", ) tdenv.DEBUG0("{} updated.", csvPath) return station
if tdStn: yield tdStn, eddbStn updateStation = tdb.updateLocalStation bool_trans = {None: '?', 0: 'N', 1: 'Y'} updates = 0 for tdStn, eddbStn in matching_stations(): mps = eddbStn['max_landing_pad_size'] or '?' if updateStation( station=tdStn, lsFromStar=eddbStn['distance_to_star'], maxPadSize=mps, market=bool_trans[eddbStn['has_commodities']], blackMarket=bool_trans[eddbStn['has_blackmarket']], shipyard=bool_trans[eddbStn['has_shipyard']], outfitting=bool_trans[eddbStn['has_outfitting']], rearm=bool_trans[eddbStn['has_rearm']], refuel=bool_trans[eddbStn['has_refuel']], repair=bool_trans[eddbStn['has_repair']], modified='now', commit=False, ): updates += 1 if updates: tdb.getDB().commit() csvexport.exportTableToFile(tdb, tdb.tdenv, "Station") print("Updated Station.csv: {} updates".format(updates))
def run(self): tdb, tdenv = self.tdb, self.tdenv # Connect to the API, authenticate, and pull down the commander # /profile. api = EDAPI(cookiefile=str(self.cookiePath)) # Sanity check that the commander is docked. Otherwise we will get a # mismatch between the last system and last station. if not api.profile['commander']['docked']: print('Commander not docked. Aborting!') return False # Figure out where we are. system = api.profile['lastSystem']['name'] station = api.profile['lastStarport']['name'] place = '@{}/{}'.format(system.upper(), station) print(place) # Reload the cache. tdenv.DEBUG0("Checking the cache") tdb.close() tdb.reloadCache() tdb.load( maxSystemLinkLy=tdenv.maxSystemLinkLy, ) tdb.close() # Check to see if this system is in the Stations file try: station_lookup = tdb.lookupPlace(place) except LookupError: station_lookup = None print(station_lookup) # The station isn't known. Add it. if not station_lookup: print('Station unknown.') print('Adding:', place) lsFromStar = input( "Distance from star (enter for 0): " ) or 0 lsFromStar = int(lsFromStar) blackMarket = input( "Black market present (Y, N or enter for ?): " ) or '?' maxPadSize = input( "Max pad size (S, M, L or enter for ?): " ) or '?' outfitting = input( "Outfitting present (Y, N or enter for ?): " ) or '?' rearm = input( "Rearm present (Y, N or enter for ?): " ) or '?' refuel = input( "Refuel present (Y, N or enter for ?): " ) or '?' repair = input( "Repair present (Y, N or enter for ?): " ) or '?' # This is unreliable, so default to unknown. if 'commodities' in api.profile['lastStarport']: market = 'Y' else: market = '?' # This is also unreliable, so default to unknown. if 'ships' in api.profile['lastStarport']: shipyard = 'Y' else: shipyard = '?' system_lookup = tdb.lookupSystem(system) if tdb.addLocalStation( system=system_lookup, name=station, lsFromStar=lsFromStar, blackMarket=blackMarket, maxPadSize=maxPadSize, market=market, shipyard=shipyard, outfitting=outfitting, rearm=rearm, refuel=refuel, repair=repair ): lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "Station" ) tdenv.NOTE("{} updated.", csvPath) station_lookup = tdb.lookupPlace(place) station_lookup = tdb.lookupStation(station, system) else: # See if we need to update the info for this station. lsFromStar = station_lookup.lsFromStar blackMarket = station_lookup.blackMarket maxPadSize = station_lookup.maxPadSize market = station_lookup.market shipyard = station_lookup.shipyard outfitting = station_lookup.outfitting rearm = station_lookup.rearm refuel = station_lookup.refuel repair = station_lookup.repair if lsFromStar == 0: lsFromStar = input( "Update distance from star (enter for 0): " ) or 0 lsFromStar = int(lsFromStar) if blackMarket is '?': blackMarket = input( "Update black market present (Y, N or enter for ?): " ) or '?' if maxPadSize is '?': maxPadSize = input( "Update max pad size (S, M, L or enter for ?): " ) or '?' if outfitting is '?': outfitting = input( "Update outfitting present (Y, N or enter for ?): " ) or '?' if rearm is '?': rearm = input( "Update rearm present (Y, N or enter for ?): " ) or '?' if refuel is '?': refuel = input( "Update refuel present (Y, N or enter for ?): " ) or '?' if repair is '?': repair = input( "Update repair present (Y, N or enter for ?): " ) or '?' # This is unreliable, so default to unchanged. if 'commodities' in api.profile['lastStarport']: market = 'Y' # This is also unreliable, so default to unchanged. if 'ships' in api.profile['lastStarport']: shipyard = 'Y' if ( lsFromStar != station_lookup.lsFromStar or blackMarket != station_lookup.blackMarket or maxPadSize != station_lookup.maxPadSize or market != station_lookup.market or shipyard != station_lookup.shipyard or outfitting != station_lookup.outfitting or rearm != station_lookup.rearm or refuel != station_lookup.refuel or repair != station_lookup.repair ): if tdb.updateLocalStation( station=station_lookup, lsFromStar=lsFromStar, blackMarket=blackMarket, maxPadSize=maxPadSize, market=market, shipyard=shipyard, outfitting=outfitting, rearm=rearm, refuel=refuel, repair=repair ): lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "Station", ) tdenv.NOTE("{} updated.", csvPath) # If a shipyard exists, update the ship vendor list. if 'ships' in api.profile['lastStarport']: ships = list( api.profile['lastStarport']['ships']['shipyard_list'].keys() ) for ship in api.profile['lastStarport']['ships']['unavailable_list']: ships.append(ship['name']) db = tdb.getDB() for ship in ships: ship_lookup = tdb.lookupShip(ship_names[ship]) db.execute( """ REPLACE INTO ShipVendor (ship_id, station_id) VALUES (?, ?) """, [ship_lookup.ID, station_lookup.ID] ) db.commit() tdenv.NOTE("Updated {} ships in {} shipyard.", len(ships), place) lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "ShipVendor", ) # Some sanity checking on the market. if 'commodities' not in api.profile['lastStarport']: print( 'The API did not return a commodity market for this station.' ) print( 'If you think this is wrong, try again. The API will ' 'occasionally skip the market.' ) return False # Create the import file. with open(self.filename, 'w', encoding="utf-8") as f: f.write("@ {}/{}\n".format(system, station)) eddn_market = [] for commodity in api.profile['lastStarport']['commodities']: if commodity['categoryname'] in cat_ignore: continue if commodity['categoryname'] in cat_correct: commodity['categoryname'] = cat_correct[commodity['categoryname']] if commodity['name'] in comm_correct: commodity['name'] = comm_correct[commodity['name']] # Populate EDDN if self.getOption("eddn"): eddn_market.append( { "name": commodity['name'], "buyPrice": int(commodity['buyPrice']), "supply": int(commodity['stock']), "supplyLevel": EDDN._levels[int(commodity['stockBracket'])], "sellPrice": int(commodity['sellPrice']), "demand": int(commodity['demand']), "demandLevel": EDDN._levels[int(commodity['demandBracket'])] } ) f.write("\t+ {}\n".format(commodity['categoryname'])) def commodity_int(key): try: commodity[key] = int(commodity[key]) except (ValueError, KeyError): commodity[key] = 0 commodity_int('stock') commodity_int('demand') commodity_int('demandBracket') commodity_int('stockBracket') # If stock is zero, list it as unavailable. if not commodity['stock']: commodity['stock'] = '-' else: demand = bracket_levels[commodity['stockBracket']] commodity['stock'] = str(commodity['stock'])+demand # If demand is zero, zero out the sell price. if not (commodity['demand'] and commodity['demandBracket']): commodity['demand'] = '?' commodity['sellPrice'] = 0 else: demand = bracket_levels[commodity['demandBracket']] commodity['demand'] = str(commodity['demand'])+demand f.write( "\t\t{} {} {} {} {}\n".format( commodity['name'], commodity['sellPrice'], commodity['buyPrice'], commodity['demand'], commodity['stock'], )) tdenv.ignoreUnknown = True cache.importDataFromFile( tdb, tdenv, pathlib.Path(self.filename), ) # Import EDDN if self.getOption("eddn"): print('Posting prices to EDDN...') con = EDDN( api.profile['commander']['name'], 'EDAPI Trade Dangerous Plugin', __version__ ) con._debug = False con.publishCommodities( system, station, eddn_market ) # We did all the work return False
def updateJournalSysList(self): """ check the found systems and add them to the DB if new. """ tdb, tdenv = self.tdb, self.tdenv optShow = self.getOption("show") if not optShow: try: idJournal = tdb.lookupAdded(self.ADDED_NAME) except KeyError: tdenv.WARN("Entry '{}' not found in 'Added' table.", self.ADDED_NAME) tdenv.WARN("Trying to add it myself.") db = tdb.getDB() cur = db.cursor() cur.execute("INSERT INTO Added(name) VALUES(?)", [self.ADDED_NAME]) db.commit() tdenv.NOTE("Export Table 'Added'") _, path = csvexport.exportTableToFile(tdb, tdenv, "Added") pass addCount = oldCount = newCount = 0 for sysName in sorted(self.sysList): sysPosX, sysPosY, sysPosZ, sysDate = self.sysList[sysName] utcDate = sysDate.astimezone( timezone.utc).strftime('%Y-%m-%d %H:%M:%S') tdenv.DEBUG0("log system '{}' ({}, {}, {}, '{}')", sysName, sysPosX, sysPosY, sysPosZ, utcDate) if sysName.upper() in self.ignoreSysNames: tdenv.NOTE("Ignoring system: '{}'", sysName) continue systemTD = tdb.systemByName.get(sysName.upper(), None) if systemTD: # we allready know the system, check coords tdenv.DEBUG0("Old system '{}' ({}, {}, {})", systemTD.dbname, systemTD.posX, systemTD.posY, systemTD.posZ) oldCount += 1 if not (systemTD.posX == sysPosX and systemTD.posY == sysPosY and systemTD.posZ == sysPosZ): tdenv.WARN("System '{}' has different coordinates:", sysName) tdenv.WARN(" database: {}, {}, {}", systemTD.posX, systemTD.posY, systemTD.posZ) tdenv.WARN(" Journal: {}, {}, {}", sysPosX, sysPosY, sysPosZ) else: # it's a new system newCount += 1 if optShow: # display only tdenv.NOTE("New system '{}' ({}, {}, {}, '{}')", sysName, sysPosX, sysPosY, sysPosZ, utcDate) else: # add it to the database # the function will output something tdb.addLocalSystem(sysName.upper(), sysPosX, sysPosY, sysPosZ, added=self.ADDED_NAME, modified=utcDate, commit=False) addCount += 1 # output statistics allCount = oldCount + newCount tdenv.NOTE( "Found {:>3} System{} altogether.", allCount, "" if allCount == 1 else "s", ) for iCount, iText in [ (oldCount, "old"), (newCount, "new"), (addCount, "added"), ]: tdenv.NOTE(" {:>3} {}", iCount, iText) if addCount: tdb.getDB().commit() tdenv.NOTE("Export Table 'System'") _, path = csvexport.exportTableToFile(tdb, tdenv, "System")
def updateJournalStnList(self): """ check the found stations and add them to the DB if new or update them in the DB if changed. """ tdb, tdenv = self.tdb, self.tdenv optShow = self.getOption("show") addCount = oldCount = newCount = updCount = 0 for sysName in sorted(self.stnList): if sysName.upper() in self.ignoreSysNames: tdenv.NOTE("Ignoring system: '{}'", sysName) continue system = tdb.systemByName.get(sysName.upper(), None) if not (system or optShow): # only warn if we are not in show mode # otherwise we could have addded the system before tdenv.WARN("System '{}' unknown.", sysName) continue for stnName in sorted(self.stnList[sysName]): jrnStation = self.stnList[sysName][stnName] utcDate = jrnStation.modified.astimezone( timezone.utc).strftime('%Y-%m-%d %H:%M:%S') station = None if system: # system could be None in show mode and the lookup # function would try very hard to find the station try: station = tdb.lookupStation(stnName, system) except LookupError: pass if (sysName, stnName) in self.blkList: # BlackMarket found jrnStation.blackMarket = "Y" elif station: if jrnStation.blackMarket == "?": # don't change current value if new one is unknown jrnStation.blackMarket = station.blackMarket tdenv.DEBUG0("log station '{}/{}' ({}, '{}')", sysName, stnName, str(jrnStation), utcDate) if not station: # must be a new station newCount += 1 if optShow: # display only tdenv.NOTE("New station '{}/{}' ({}, '{}')", sysName, stnName, str(jrnStation), utcDate) else: # add it to the database # the function will output something station = tdb.addLocalStation( system=system, name=stnName, lsFromStar=jrnStation.lsFromStar, blackMarket=jrnStation.blackMarket, maxPadSize=jrnStation.maxPadSize, market=jrnStation.market, shipyard=jrnStation.shipyard, outfitting=jrnStation.outfitting, rearm=jrnStation.rearm, refuel=jrnStation.refuel, repair=jrnStation.repair, planetary=jrnStation.planetary, modified=utcDate, commit=False, ) addCount += 1 else: oldCount += 1 tdenv.DEBUG0( "Old station '{}' ({}ls Pad:{} Mkt:{} Blk:{} Shp:{} Out:{} Arm:{} Ref:{} Rep:{} Plt:{})", station.name(), station.lsFromStar, station.maxPadSize, station.market, station.blackMarket, station.shipyard, station.outfitting, station.rearm, station.refuel, station.repair, station.planetary) if not optShow: if (station.lsFromStar != jrnStation.lsFromStar and station.blackMarket == jrnStation.blackMarket and station.maxPadSize == jrnStation.maxPadSize and station.market == jrnStation.market and station.shipyard == jrnStation.shipyard and station.outfitting == jrnStation.outfitting and station.rearm == jrnStation.rearm and station.refuel == jrnStation.refuel and station.repair == jrnStation.repair and station.planetary == jrnStation.planetary): # ignore 15% deviation if it's the only change lsMin = int(station.lsFromStar * 0.85) lsMax = int(station.lsFromStar * 1.15 + 1) if lsMin <= jrnStation.lsFromStar <= lsMax: tdenv.DEBUG0( "ignore 15% deviation ({}ls ~ {}ls)", jrnStation.lsFromStar, station.lsFromStar) jrnStation.lsFromStar = station.lsFromStar # the function will do it's own check and output # something if the station is updated if tdb.updateLocalStation( station=station, lsFromStar=jrnStation.lsFromStar, blackMarket=jrnStation.blackMarket, maxPadSize=jrnStation.maxPadSize, market=jrnStation.market, shipyard=jrnStation.shipyard, outfitting=jrnStation.outfitting, rearm=jrnStation.rearm, refuel=jrnStation.refuel, repair=jrnStation.repair, planetary=jrnStation.planetary, modified=utcDate, commit=False, ): updCount += 1 # output statistics allCount = oldCount + newCount tdenv.NOTE( "Found {:>3} Station{} altogether.", allCount, "" if allCount == 1 else "s", ) for iCount, iText in [ (oldCount, "old"), (updCount, "updated"), (newCount, "new"), (addCount, "added"), ]: tdenv.NOTE(" {:>3} {}", iCount, iText) if (updCount + addCount) > 0: tdb.getDB().commit() tdenv.NOTE("Export Table 'Station'") _, path = csvexport.exportTableToFile(tdb, tdenv, "Station")
def run(self): tdb, tdenv = self.tdb, self.tdenv # first check for EDCD if self.getOption("edcd"): # Call the EDCD plugin try: import plugins.edcd_plug as EDCD except: raise plugins.PluginException("EDCD plugin not found.") tdenv.NOTE("Calling the EDCD plugin.") edcdPlugin = EDCD.ImportPlugin(tdb, tdenv) edcdPlugin.options["csvs"] = True edcdPlugin.run() tdenv.NOTE("Going back to EDAPI.\n") # now load the mapping tables itemMap = mapping.FDEVMappingItems(tdb, tdenv) shipMap = mapping.FDEVMappingShips(tdb, tdenv) # Connect to the API, authenticate, and pull down the commander # /profile. if self.getOption("test"): tdenv.WARN("#############################") tdenv.WARN("### EDAPI in test mode. ###") tdenv.WARN("#############################") apiED = namedtuple('EDAPI', ['profile','text']) try: proPath = pathlib.Path(self.getOption("test")) except TypeError: raise plugins.PluginException( "Option 'test' must be a file name" ) if proPath.exists(): with proPath.open() as proFile: api = apiED( profile = json.load(proFile), text = '{{"mode":"test","file":"{}"}}'.format(str(proPath)) ) else: raise plugins.PluginException( "JSON-file '{}' not found.".format(str(proPath)) ) else: api = EDAPI(cookiefile=str(self.cookiePath)) self.edAPI = api # Sanity check that the commander is docked. Otherwise we will get a # mismatch between the last system and last station. if not api.profile['commander']['docked']: print('Commander not docked. Aborting!') return False # save profile if requested if self.getOption("save"): saveName = 'tmp/profile.' + time.strftime('%Y%m%d_%H%M%S') + '.json' with open(saveName, 'w', encoding="utf-8") as saveFile: saveFile.write(api.text) print('API response saved to: {}'.format(saveName)) # Figure out where we are. sysName = api.profile['lastSystem']['name'] stnName = api.profile['lastStarport']['name'] print('@{}/{}'.format(sysName.upper(), stnName)) # Reload the cache. tdenv.DEBUG0("Checking the cache") tdb.close() tdb.reloadCache() tdb.load( maxSystemLinkLy=tdenv.maxSystemLinkLy, ) tdb.close() # Check to see if this system is in the database try: system = tdb.lookupSystem(sysName) except LookupError: raise plugins.PluginException( "System '{}' unknown.".format(sysName) ) # Check to see if this station is in the database try: station = tdb.lookupStation(stnName, system) except LookupError: station = None # New or update station data station = self.askForStationData(system, stnName=stnName, station=station) # If a shipyard exists, make the ship lists shipList = [] eddn_ships = [] if ((station.shipyard == "Y") and ('ships' in api.profile['lastStarport']) ): if 'shipyard_list' in api.profile['lastStarport']['ships']: for ship in api.profile['lastStarport']['ships']['shipyard_list'].values(): shipList.append(shipMap.mapID(ship['id'], ship['name'])) eddn_ships.append(ship['name']) if 'unavailable_list' in api.profile['lastStarport']['ships']: for ship in api.profile['lastStarport']['ships']['unavailable_list']: shipList.append(shipMap.mapID(ship['id'], ship['name'])) eddn_ships.append(ship['name']) if self.getOption("csvs"): exportCSV = False db = tdb.getDB() # first delete all ships if ((len(shipList) > 0) or (station.shipyard == "N")): # but only if there should be no shipyard or there is a new list delRows = db.execute( """ DELETE FROM ShipVendor WHERE station_id = ? """, [station.ID] ).rowcount if delRows > 0: exportCSV = True tdenv.NOTE( "Deleted {} ships in '{}' shipyard.", delRows, station.name() ) # and now add the shipyard list for ship in shipList: ship_lookup = tdb.lookupShip(ship) db.execute( """ INSERT INTO ShipVendor(ship_id, station_id) VALUES(?, ?) """, [ship_lookup.ID, station.ID] ) exportCSV = True db.commit() if exportCSV: tdenv.NOTE( "Added {} ships in '{}' shipyard.", len(shipList), station.name() ) lines, csvPath = csvexport.exportTableToFile( tdb, tdenv, "ShipVendor", ) tdenv.DEBUG0("{} updated.", csvPath) # If a market exists, make the item lists itemList = [] eddn_market = [] if ((station.market == "Y") and ('commodities' in api.profile['lastStarport']) ): for commodity in api.profile['lastStarport']['commodities']: if commodity['categoryname'] in cat_ignore: continue itmName = itemMap.mapID(commodity['id'], commodity['name']) def commodity_int(key): try: ret = int(float(commodity[key])+0.5) except (ValueError, KeyError): ret = 0 return ret itmSupply = commodity_int('stock') itmDemand = commodity_int('demand') itmSupplyLevel = commodity_int('stockBracket') itmDemandLevel = commodity_int('demandBracket') itmBuyPrice = commodity_int('buyPrice') itmSellPrice = commodity_int('sellPrice') demandLevel = True supplyLevel = True if itmBuyPrice == 0: # If there is not buyPrice, ignore stock supplyLevel = False itmSupply = 0 itmSupplyLevel = 0 tdSupply = "-" tdDemand = "{}{}".format( itmDemand, bracket_levels[itmDemandLevel] ) else: # otherwise don't care about demand demandLevel = False itmDemand = 0 itmDemandLevel = 0 tdDemand = "?" tdSupply = "{}{}".format( itmSupply, bracket_levels[itmSupplyLevel] ) itemTD = ( itmName, itmSellPrice, itmBuyPrice, tdDemand, tdSupply, ) itemList.append(itemTD) # Populate EDDN if self.getOption("eddn"): itemEDDN = { "name": commodity['name'], "meanPrice": commodity_int('meanPrice'), "buyPrice": commodity_int('buyPrice'), "stock": commodity_int('stock'), "stockBracket": commodity['stockBracket'], "sellPrice": commodity_int('sellPrice'), "demand": commodity_int('demand'), "demandBracket": commodity['demandBracket'], } if len(commodity['statusFlags']) > 0: itemEDDN["statusFlags"] = commodity['statusFlags'] eddn_market.append(itemEDDN) if itemList: # Create the import file. with open(self.filename, 'w', encoding="utf-8") as f: # write System/Station line f.write("@ {}/{}\n".format(sysName, stnName)) # write Item lines (category lines are not needed) for itemTD in itemList: f.write("\t\t%s %s %s %s %s\n" % itemTD) tdenv.ignoreUnknown = True cache.importDataFromFile( tdb, tdenv, pathlib.Path(self.filename), ) # Import EDDN if self.getOption("eddn"): con = EDDN( api.profile['commander']['name'], self.getOption("name"), 'EDAPI Trade Dangerous Plugin', __version__ ) if self.getOption("test"): con._debug = True else: con._debug = False if eddn_market: print('Posting commodities to EDDN...') con.publishCommodities( sysName, stnName, eddn_market ) if eddn_ships: print('Posting shipyard to EDDN...') con.publishShipyard( sysName, stnName, eddn_ships ) if ((station.outfitting == "Y") and ('modules' in api.profile['lastStarport']) ): eddn_modules = [] for module in api.profile['lastStarport']['modules'].values(): # see: https://github.com/jamesremuscat/EDDN/wiki addModule = False if module['name'].startswith(('Hpt_', 'Int_')) or module['name'].find('_Armour_') > 0: if module.get('sku', None) in ( None, 'ELITE_HORIZONS_V_PLANETARY_LANDINGS' ): if module['name'] != 'Int_PlanetApproachSuite': addModule = True if addModule: eddn_modules.append(module['name']) elif self.getOption("test"): tdenv.NOTE("Ignored module ID: {}, name: {}", module['id'], module['name']) if eddn_modules: print('Posting outfitting to EDDN...') con.publishOutfitting( sysName, stnName, sorted(eddn_modules) ) # We did all the work return False