diff --git a/gui/fitCommands/helpers.py b/gui/fitCommands/helpers.py
index 23f775a5e..464e3bf0e 100644
--- a/gui/fitCommands/helpers.py
+++ b/gui/fitCommands/helpers.py
@@ -324,7 +324,8 @@ def activeStateLimit(itemIdentity):
'microJumpDrive', 'microJumpPortalDrive', 'emergencyHullEnergizer',
'cynosuralGeneration', 'jumpPortalGeneration', 'jumpPortalGenerationBO',
'cloneJumpAccepting', 'cloakingWarpSafe', 'cloakingPrototype', 'cloaking',
- 'massEntanglerEffect5', 'electronicAttributeModifyOnline', 'targetPassively'
+ 'massEntanglerEffect5', 'electronicAttributeModifyOnline', 'targetPassively',
+ 'cargoScan', 'shipScan', 'surveyScan'
}.intersection(item.effects):
return FittingModuleState.ONLINE
return FittingModuleState.ACTIVE
diff --git a/service/marketSources/__init__.py b/service/marketSources/__init__.py
index 70d9f67ad..d8962c198 100644
--- a/service/marketSources/__init__.py
+++ b/service/marketSources/__init__.py
@@ -1 +1 @@
-__all__ = ['evemarketer', 'evepraisal', 'evemarketdata', 'fuzzwork']
+__all__ = ['evemarketer', 'evepraisal', 'evemarketdata', 'fuzzwork', 'cevemarket']
diff --git a/service/marketSources/cevemarket.py b/service/marketSources/cevemarket.py
new file mode 100644
index 000000000..fdc02a0d5
--- /dev/null
+++ b/service/marketSources/cevemarket.py
@@ -0,0 +1,86 @@
+# =============================================================================
+# Copyright (C) 2020 Copy Liu
+#
+# This file is part of pyfa.
+#
+# pyfa is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# pyfa is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with pyfa. If not, see .
+# =============================================================================
+
+
+from xml.dom import minidom
+
+from logbook import Logger
+
+from eos.saveddata.price import PriceStatus
+from service.network import Network
+from service.price import Price
+
+pyfalog = Logger(__name__)
+
+
+
+class CEveMarketBase:
+ @staticmethod
+ def fetchPrices(priceMap, fetchTimeout, system=None, serenity=False):
+ params = {'typeid': {typeID for typeID in priceMap}}
+ if system is not None:
+ params['usesystem'] = system
+ baseurl = 'https://www.ceve-market.org/api/marketstat' if serenity else 'https://www.ceve-market.org/tqapi/marketstat'
+ network = Network.getInstance()
+ data = network.get(url=baseurl, type=network.PRICES, params=params, timeout=fetchTimeout)
+ xml = minidom.parseString(data.text)
+ types = xml.getElementsByTagName('marketstat').item(0).getElementsByTagName('type')
+ # Cycle through all types we've got from request
+ for type_ in types:
+ # Get data out of each typeID details tree
+ typeID = int(type_.getAttribute('id'))
+ sell = type_.getElementsByTagName('sell').item(0)
+ # If price data wasn't there, skip the item
+ try:
+ percprice = float(sell.getElementsByTagName('percentile').item(0).firstChild.data)
+ except (TypeError, ValueError):
+ pyfalog.warning('Failed to get price for: {0}', type_)
+ continue
+
+ # Price is 0 if evemarketer has info on this item, but it is not available
+ # for current scope limit. If we provided scope limit - make sure to skip
+ # such items to check globally, and do not skip if requested globally
+ if percprice == 0 and system is not None:
+ continue
+ priceMap[typeID].update(PriceStatus.fetchSuccess, percprice)
+ del priceMap[typeID]
+
+
+class CEveMarketTq(CEveMarketBase):
+ name = 'www.ceve-market.org (Tranquility)' #let me at last
+
+ def __init__(self, priceMap, system, fetchTimeout):
+ # Try selected system first
+ self.fetchPrices(priceMap, max(2 * fetchTimeout / 3, 2), system, serenity=False)
+ # If price was not available - try globally
+ if priceMap:
+ self.fetchPrices(priceMap, max(fetchTimeout / 3, 2), serenity=False)
+
+class CEveMarketCn(CEveMarketBase):
+ name = 'www.ceve-market.org (Serenity)' #let me at last
+
+ def __init__(self, priceMap, system, fetchTimeout):
+ # Try selected system first
+ self.fetchPrices(priceMap, max(2 * fetchTimeout / 3, 2), system, serenity=True)
+ # If price was not available - try globally
+ if priceMap:
+ self.fetchPrices(priceMap, max(fetchTimeout / 3, 2), serenity=True)
+
+Price.register(CEveMarketCn)
+Price.register(CEveMarketTq)
diff --git a/service/port/esi.py b/service/port/esi.py
index 061ad514c..905dc75f1 100644
--- a/service/port/esi.py
+++ b/service/port/esi.py
@@ -72,7 +72,7 @@ def exportESI(ofit, exportCharges, callback):
# 2017/03/29 NOTE: "<" or "<" is Ignored
# fit['description'] = "" % ofit.ID
- fit['description'] = ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes if ofit.notes is not None else ""
+ fit['description'] = "" if ofit.notes is None else ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes
fit['items'] = []
slotNum = {}
diff --git a/service/price.py b/service/price.py
index 8a2e30d54..14623bbe0 100644
--- a/service/price.py
+++ b/service/price.py
@@ -273,4 +273,4 @@ class PriceWorkerThread(threading.Thread):
# Import market sources only to initialize price source modules, they register on their own
-from service.marketSources import evemarketer, evemarketdata, evepraisal, fuzzwork # noqa: E402
+from service.marketSources import evemarketer, evemarketdata, evepraisal, fuzzwork, cevemarket # noqa: E402