#!/usr/bin/python3 import sys, os, os.path, re, cgi # Configuration variables realmName = 'maiev' auctionHouseName = 'horde' wowdir = '/home/gregstoll/.cedega/World of Warcraft/c_drive/Program Files/World of Warcraft' accountName = 'gregstoll' auctionDataFileName = os.path.join(wowdir, 'WTF', 'Account', accountName.upper(), 'SavedVariables', 'Auctioneer.lua') #auctionDatas = [{'description': "Rilinar's data (less accurate)", 'fileName': auctionDataFileName}, # {'description': "Falandre's data (more accurate)", 'fileName': '/home/gregstoll/projects/auctioneerlookup/Auctioneernew.lua'}] auctionDatas = [{'description': "Tsouzer's data", 'fileName': auctionDataFileName}] auctionHouseSpecifier = realmName + '-' + auctionHouseName def getKeyName(line): if (line.startswith('[')): endKeyIndex = line.find(']', 1) if (endKeyIndex > -1): key = line[1:endKeyIndex] if (key.startswith('"')): key = key[1:] if (key.endswith('"')): key = key[:-1] return key else: print("Couldn't find end of key with line \"%s\"!" % line) else: # We're in the case of a top-level object. Look for that. keyMatch = re.compile(r'(\w+)').match(line) if (keyMatch): key = keyMatch.group(1) return key else: return None def getKeyAndValue(line): key = getKeyName(line) if (key != None): startIndex = len(key) equalsSignIndex = line.find('=', startIndex) if (equalsSignIndex > -1): value = line[equalsSignIndex+1:] else: value = None else: value = line if (value != None): value = value.strip() if (value.startswith('"')): value = value[1:] if (value.endswith('"')): value = value[:-1] elif (value.endswith('",')): value = value[:-2] elif (value.endswith(',')): value = value[:-1] return key, value # This method tests curPathList to see if it conforms to sectionPath. # ? means match any one 'directory'. # * means match all directories. You can't have another element after a *. def testSectionPath(sectionPathList, curPathList): # Start checking at the beginning. index = 0 for sectPathElem in sectionPathList: if (index >= len(curPathList)): return False if (sectPathElem == "*"): return True elif (sectPathElem != '?'): if (sectPathElem != curPathList[index]): return False index = index + 1 if (len(curPathList) != index): return False return True def doLookupDefer(fileName, sectionPath, matchFunction, callbackFunction, previousDeferObject=None): if (previousDeferObject == None): return {'fileName' : fileName, 'sectionPaths' : [sectionPath], 'matchFunctions' : [matchFunction], 'callbackFunctions' : [callbackFunction]} else: if (previousDeferObject['fileName'] != fileName): print("Filename mismatch!") raise Exception("Filename mismatch!") previousDeferObject['sectionPaths'].append(sectionPath) previousDeferObject['matchFunctions'].append(matchFunction) previousDeferObject['callbackFunctions'].append(callbackFunction) return previousDeferObject # What we would like to do is parse this properly and look up things. However, # this is impractical given the size of the file (it takes 10 seconds or so # just to parse). So we do an ad-hoc thing. def runDeferredLookup(deferObject): file = open(deferObject['fileName'], 'r') numLines = 0 curPath = [] sectionPathsList = [sectionPath.split('/') for sectionPath in deferObject['sectionPaths']] isInSectionPaths = [testSectionPath(sectionPathList, curPath) for sectionPathList in sectionPathsList] for line in file: line = line.strip() if (line.endswith('{')): key = getKeyName(line) if (key): curPath.append(key) else: print("Couldn't find key with line \"%s\"!" % line) isInSectionPaths = [testSectionPath(sectionPathList, curPath) for sectionPathList in sectionPathsList] elif (line.endswith('}') or line.endswith('},')): curPath.pop() isInSectionPaths = [testSectionPath(sectionPathList, curPath) for sectionPathList in sectionPathsList] else: for i in range(len(isInSectionPaths)): if (isInSectionPaths[i]): key, value = getKeyAndValue(line) #if (key): if (deferObject['matchFunctions'][i](key, value, curPath)): #print "Got it in line (path %s): %s" % ('/'.join(curPath), line) deferObject['callbackFunctions'][i](key, value, curPath) numLines = numLines + 1 file.close() # What we would like to do is parse this properly and look up things. However, # this is impractical given the size of the file (it takes 10 seconds or so # just to parse). So we do an ad-hoc thing. def doLookup(fileName, sectionPath, matchFunction, callbackFunction): deferObject = doLookupDefer(fileName, sectionPath, matchFunction, callbackFunction) runDeferredLookup(deferObject) def appendItemToList(value, target): target[0].append(value[:value.find(';')]) def findAllItemPrefixes(fileName, prefix): toReturn = [[]] prefix = prefix.lower() doLookup(fileName, "AuctioneerItemDB/items", lambda key, value, curPath: value.lower().startswith(prefix), lambda key, value, curPath: appendItemToList(value, toReturn)) return toReturn def setKey(key, value, target): target[0] = key # Find the real name of the item and return it. target[1] = value def findItemKey(fileName, itemName): toReturn = [None, None] itemName = itemName.lower() doLookup(fileName, "AuctioneerItemDB/items", lambda key, value, curPath: value.lower().startswith(itemName + ';'), lambda key, value, curPath: setKey(key, value[:value.index(';')], toReturn)) return toReturn def setBuyoutInfo(value, target): compactBuyouts = value.split(':') realBuyouts = [] for buyout in compactBuyouts: if 'x' in buyout: splitInfo = buyout.split('x') splitInfo = [int(x) for x in splitInfo] for i in range(0,splitInfo[1]): realBuyouts.append(splitInfo[0]) else: realBuyouts.append(int(buyout)) # Now, find the median. numBuyouts = len(realBuyouts) if (numBuyouts > 0): if (numBuyouts % 2 == 0): median = (realBuyouts[(numBuyouts/2) - 1] + realBuyouts[numBuyouts/2]) / 2 else: median = realBuyouts[(numBuyouts-1)/2] target['buyoutMedian'] = median target['buyoutCount'] = numBuyouts def getAuctionBuyoutData(buyoutData): toReturn = '' #for buyoutKey in ('histcount', 'histmed', 'snapcount', 'snapmed'): for buyoutKey in ('buyoutMedian','buyoutCount'): if buyoutKey in buyoutData: toReturn += '<%s>%s' % (buyoutKey, buyoutData[buyoutKey], buyoutKey) return toReturn def processAuctionData(data, target): #print "Got data: %s" % data prices = data aCount, minCount, minPrice, bidCount, bidPrice, buyCount, buyPrice = prices.split(';') # FFV - surely there's a better way to do this section! aCount = int(aCount) minCount = int(minCount) minPrice = int(minPrice) bidCount = int(bidCount) bidPrice = int(bidPrice) buyCount = int(buyCount) buyPrice = int(buyPrice) if (aCount > 0): avgMin = minPrice / minCount bidPct = (100 * bidCount) / minCount avgBid = 0 if (bidCount > 0): avgBid = bidPrice / bidCount buyPct = (100 * buyCount) / minCount avgBuy = 0 if (buyCount > 0): avgBuy = buyPrice / buyCount toReturn = '' toReturn += '%d' % aCount if (aCount > 0): toReturn += '%d' % avgMin toReturn += '%d' % bidPct toReturn += '%d' % avgBid toReturn += '%d' % buyPct toReturn += '%d' % avgBuy target[0] = toReturn def setLastScanAge(value, target): target[0] = value[:value.index(';')] def searchForItem(dataFileName, prefix): [allItemNames] = findAllItemPrefixes(dataFileName, prefix) toReturn = '' toReturn += '%s' % prefix allItemNames.sort() for itemName in allItemNames: toReturn += '%s' % itemName toReturn += '' return toReturn def getAuctionData(itemName): itemName = itemName.strip() firstAuctionDataFileName = auctionDatas[0]['fileName'] if (itemName[-1] == '*'): return searchForItem(firstAuctionDataFileName, itemName[:-1]) [itemKey, realItemName] = findItemKey(auctionDataFileName, itemName) toReturn = '' if (realItemName != None): toReturn += '%s' % realItemName if (itemKey): for data in auctionDatas: toReturn += "" % data['description'] lastScanAge = [None] buyoutInfo = {} output = [None] # FFV - pretty eot sure about this deferLookup = doLookupDefer(data['fileName'], "AuctioneerSnapshotDB/" + auctionHouseSpecifier + "/updates", lambda key, value, curPath: True, lambda key, value, curPath: setLastScanAge(value, lastScanAge)) # TODO - lookup in AuctioneerSnapshotDB/maiev-horde/auctions # TODO - Also, AuctioneerHistoryDB/maiev-horde/buyoutPrices for buyout prices (do median) # deferLookup = doLookupDefer(data['fileName'], "AuctionConfig/stats/?/" + auctionHouseSpecifier, lambda key, value, curPath: (key == itemKey), lambda key, value, curPath: setMedianInfo(value, curPath, medianStats), deferLookup) deferLookup = doLookupDefer(data['fileName'], "AuctioneerHistoryDB/" + auctionHouseSpecifier + "/totals", lambda key, value, curPath: (key == itemKey), lambda key, value, curPath: processAuctionData(value, output), deferLookup) deferLookup = doLookupDefer(data['fileName'], "AuctioneerHistoryDB/" + auctionHouseSpecifier + "/buyoutPrices", lambda key, value, curPath: (key == itemKey), lambda key, value, curPath: setBuyoutInfo(value, buyoutInfo), deferLookup) runDeferredLookup(deferLookup) if (lastScanAge[0] != None): toReturn += '%s' % lastScanAge[0] if (output[0]): toReturn += output[0] toReturn += getAuctionBuyoutData(buyoutInfo) toReturn += "" toReturn += '' return toReturn if (__name__ == '__main__'): form = cgi.FieldStorage() itemName = form.getfirst('itemName') auctionData = getAuctionData(itemName) print("Content-type: text/xml\n\n") print(auctionData)