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)
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
    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)
예제 #6
0
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
예제 #7
0
 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)
예제 #8
0
    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))
예제 #10
0
    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")
예제 #11
0
    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")
예제 #12
0
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
예제 #13
0
    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
예제 #14
0
    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))
예제 #16
0
    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
예제 #17
0
    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")
예제 #18
0
    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")
예제 #19
0
    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