mirror of https://github.com/evilhero/mylar
Removed stun library, removed more unicode conversions
This commit is contained in:
parent
143152642e
commit
95527cb27b
|
@ -1,257 +0,0 @@
|
||||||
import binascii
|
|
||||||
import logging
|
|
||||||
import random
|
|
||||||
import socket
|
|
||||||
|
|
||||||
__version__ = '0.1.0'
|
|
||||||
|
|
||||||
log = logging.getLogger("pystun")
|
|
||||||
|
|
||||||
STUN_SERVERS = (
|
|
||||||
'stun.ekiga.net',
|
|
||||||
'stun.ideasip.com',
|
|
||||||
'stun.voiparound.com',
|
|
||||||
'stun.voipbuster.com',
|
|
||||||
'stun.voipstunt.com',
|
|
||||||
'stun.voxgratia.org'
|
|
||||||
)
|
|
||||||
|
|
||||||
stun_servers_list = STUN_SERVERS
|
|
||||||
|
|
||||||
DEFAULTS = {
|
|
||||||
'stun_port': 3478,
|
|
||||||
'source_ip': '0.0.0.0',
|
|
||||||
'source_port': 54320
|
|
||||||
}
|
|
||||||
|
|
||||||
# stun attributes
|
|
||||||
MappedAddress = '0001'
|
|
||||||
ResponseAddress = '0002'
|
|
||||||
ChangeRequest = '0003'
|
|
||||||
SourceAddress = '0004'
|
|
||||||
ChangedAddress = '0005'
|
|
||||||
Username = '0006'
|
|
||||||
Password = '0007'
|
|
||||||
MessageIntegrity = '0008'
|
|
||||||
ErrorCode = '0009'
|
|
||||||
UnknownAttribute = '000A'
|
|
||||||
ReflectedFrom = '000B'
|
|
||||||
XorOnly = '0021'
|
|
||||||
XorMappedAddress = '8020'
|
|
||||||
ServerName = '8022'
|
|
||||||
SecondaryAddress = '8050' # Non standard extension
|
|
||||||
|
|
||||||
# types for a stun message
|
|
||||||
BindRequestMsg = '0001'
|
|
||||||
BindResponseMsg = '0101'
|
|
||||||
BindErrorResponseMsg = '0111'
|
|
||||||
SharedSecretRequestMsg = '0002'
|
|
||||||
SharedSecretResponseMsg = '0102'
|
|
||||||
SharedSecretErrorResponseMsg = '0112'
|
|
||||||
|
|
||||||
dictAttrToVal = {'MappedAddress': MappedAddress,
|
|
||||||
'ResponseAddress': ResponseAddress,
|
|
||||||
'ChangeRequest': ChangeRequest,
|
|
||||||
'SourceAddress': SourceAddress,
|
|
||||||
'ChangedAddress': ChangedAddress,
|
|
||||||
'Username': Username,
|
|
||||||
'Password': Password,
|
|
||||||
'MessageIntegrity': MessageIntegrity,
|
|
||||||
'ErrorCode': ErrorCode,
|
|
||||||
'UnknownAttribute': UnknownAttribute,
|
|
||||||
'ReflectedFrom': ReflectedFrom,
|
|
||||||
'XorOnly': XorOnly,
|
|
||||||
'XorMappedAddress': XorMappedAddress,
|
|
||||||
'ServerName': ServerName,
|
|
||||||
'SecondaryAddress': SecondaryAddress}
|
|
||||||
|
|
||||||
dictMsgTypeToVal = {
|
|
||||||
'BindRequestMsg': BindRequestMsg,
|
|
||||||
'BindResponseMsg': BindResponseMsg,
|
|
||||||
'BindErrorResponseMsg': BindErrorResponseMsg,
|
|
||||||
'SharedSecretRequestMsg': SharedSecretRequestMsg,
|
|
||||||
'SharedSecretResponseMsg': SharedSecretResponseMsg,
|
|
||||||
'SharedSecretErrorResponseMsg': SharedSecretErrorResponseMsg}
|
|
||||||
|
|
||||||
dictValToMsgType = {}
|
|
||||||
|
|
||||||
dictValToAttr = {}
|
|
||||||
|
|
||||||
Blocked = "Blocked"
|
|
||||||
OpenInternet = "Open Internet"
|
|
||||||
FullCone = "Full Cone"
|
|
||||||
SymmetricUDPFirewall = "Symmetric UDP Firewall"
|
|
||||||
RestricNAT = "Restric NAT"
|
|
||||||
RestricPortNAT = "Restric Port NAT"
|
|
||||||
SymmetricNAT = "Symmetric NAT"
|
|
||||||
ChangedAddressError = "Meet an error, when do Test1 on Changed IP and Port"
|
|
||||||
|
|
||||||
|
|
||||||
def _initialize():
|
|
||||||
items = dictAttrToVal.items()
|
|
||||||
for i in range(len(items)):
|
|
||||||
dictValToAttr.update({items[i][1]: items[i][0]})
|
|
||||||
items = dictMsgTypeToVal.items()
|
|
||||||
for i in range(len(items)):
|
|
||||||
dictValToMsgType.update({items[i][1]: items[i][0]})
|
|
||||||
|
|
||||||
|
|
||||||
def gen_tran_id():
|
|
||||||
a = ''.join(random.choice('0123456789ABCDEF') for i in range(32))
|
|
||||||
# return binascii.a2b_hex(a)
|
|
||||||
return a
|
|
||||||
|
|
||||||
|
|
||||||
def stun_test(sock, host, port, source_ip, source_port, send_data=""):
|
|
||||||
retVal = {'Resp': False, 'ExternalIP': None, 'ExternalPort': None,
|
|
||||||
'SourceIP': None, 'SourcePort': None, 'ChangedIP': None,
|
|
||||||
'ChangedPort': None}
|
|
||||||
str_len = "%#04d" % (len(send_data) / 2)
|
|
||||||
tranid = gen_tran_id()
|
|
||||||
str_data = ''.join([BindRequestMsg, str_len, tranid, send_data])
|
|
||||||
data = binascii.a2b_hex(str_data)
|
|
||||||
recvCorr = False
|
|
||||||
while not recvCorr:
|
|
||||||
recieved = False
|
|
||||||
count = 3
|
|
||||||
while not recieved:
|
|
||||||
log.debug("sendto: %s", (host, port))
|
|
||||||
try:
|
|
||||||
sock.sendto(data, (host, port))
|
|
||||||
except socket.gaierror:
|
|
||||||
retVal['Resp'] = False
|
|
||||||
return retVal
|
|
||||||
try:
|
|
||||||
buf, addr = sock.recvfrom(2048)
|
|
||||||
log.debug("recvfrom: %s", addr)
|
|
||||||
recieved = True
|
|
||||||
except Exception:
|
|
||||||
recieved = False
|
|
||||||
if count > 0:
|
|
||||||
count -= 1
|
|
||||||
else:
|
|
||||||
retVal['Resp'] = False
|
|
||||||
return retVal
|
|
||||||
msgtype = binascii.b2a_hex(buf[0:2])
|
|
||||||
bind_resp_msg = dictValToMsgType[msgtype] == "BindResponseMsg"
|
|
||||||
tranid_match = tranid.upper() == binascii.b2a_hex(buf[4:20]).upper()
|
|
||||||
if bind_resp_msg and tranid_match:
|
|
||||||
recvCorr = True
|
|
||||||
retVal['Resp'] = True
|
|
||||||
len_message = int(binascii.b2a_hex(buf[2:4]), 16)
|
|
||||||
len_remain = len_message
|
|
||||||
base = 20
|
|
||||||
while len_remain:
|
|
||||||
attr_type = binascii.b2a_hex(buf[base:(base + 2)])
|
|
||||||
attr_len = int(binascii.b2a_hex(buf[(base + 2):(base + 4)]), 16)
|
|
||||||
if attr_type == MappedAddress:
|
|
||||||
port = int(binascii.b2a_hex(buf[base + 6:base + 8]), 16)
|
|
||||||
ip = ".".join([
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 8:base + 9]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 9:base + 10]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 10:base + 11]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 11:base + 12]), 16))
|
|
||||||
])
|
|
||||||
retVal['ExternalIP'] = ip
|
|
||||||
retVal['ExternalPort'] = port
|
|
||||||
if attr_type == SourceAddress:
|
|
||||||
port = int(binascii.b2a_hex(buf[base + 6:base + 8]), 16)
|
|
||||||
ip = ".".join([
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 8:base + 9]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 9:base + 10]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 10:base + 11]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 11:base + 12]), 16))
|
|
||||||
])
|
|
||||||
retVal['SourceIP'] = ip
|
|
||||||
retVal['SourcePort'] = port
|
|
||||||
if attr_type == ChangedAddress:
|
|
||||||
port = int(binascii.b2a_hex(buf[base + 6:base + 8]), 16)
|
|
||||||
ip = ".".join([
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 8:base + 9]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 9:base + 10]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 10:base + 11]), 16)),
|
|
||||||
str(int(binascii.b2a_hex(buf[base + 11:base + 12]), 16))
|
|
||||||
])
|
|
||||||
retVal['ChangedIP'] = ip
|
|
||||||
retVal['ChangedPort'] = port
|
|
||||||
# if attr_type == ServerName:
|
|
||||||
# serverName = buf[(base+4):(base+4+attr_len)]
|
|
||||||
base = base + 4 + attr_len
|
|
||||||
len_remain = len_remain - (4 + attr_len)
|
|
||||||
# s.close()
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
|
|
||||||
def get_nat_type(s, source_ip, source_port, stun_host=None, stun_port=3478):
|
|
||||||
_initialize()
|
|
||||||
port = stun_port
|
|
||||||
log.debug("Do Test1")
|
|
||||||
resp = False
|
|
||||||
if stun_host:
|
|
||||||
ret = stun_test(s, stun_host, port, source_ip, source_port)
|
|
||||||
resp = ret['Resp']
|
|
||||||
else:
|
|
||||||
for stun_host in stun_servers_list:
|
|
||||||
log.debug('Trying STUN host: %s', stun_host)
|
|
||||||
ret = stun_test(s, stun_host, port, source_ip, source_port)
|
|
||||||
resp = ret['Resp']
|
|
||||||
if resp:
|
|
||||||
break
|
|
||||||
if not resp:
|
|
||||||
return Blocked, ret
|
|
||||||
log.debug("Result: %s", ret)
|
|
||||||
exIP = ret['ExternalIP']
|
|
||||||
exPort = ret['ExternalPort']
|
|
||||||
changedIP = ret['ChangedIP']
|
|
||||||
changedPort = ret['ChangedPort']
|
|
||||||
if ret['ExternalIP'] == source_ip:
|
|
||||||
changeRequest = ''.join([ChangeRequest, '0004', "00000006"])
|
|
||||||
ret = stun_test(s, stun_host, port, source_ip, source_port,
|
|
||||||
changeRequest)
|
|
||||||
if ret['Resp']:
|
|
||||||
typ = OpenInternet
|
|
||||||
else:
|
|
||||||
typ = SymmetricUDPFirewall
|
|
||||||
else:
|
|
||||||
changeRequest = ''.join([ChangeRequest, '0004', "00000006"])
|
|
||||||
log.debug("Do Test2")
|
|
||||||
ret = stun_test(s, stun_host, port, source_ip, source_port,
|
|
||||||
changeRequest)
|
|
||||||
log.debug("Result: %s", ret)
|
|
||||||
if ret['Resp']:
|
|
||||||
typ = FullCone
|
|
||||||
else:
|
|
||||||
log.debug("Do Test1")
|
|
||||||
ret = stun_test(s, changedIP, changedPort, source_ip, source_port)
|
|
||||||
log.debug("Result: %s", ret)
|
|
||||||
if not ret['Resp']:
|
|
||||||
typ = ChangedAddressError
|
|
||||||
else:
|
|
||||||
if exIP == ret['ExternalIP'] and exPort == ret['ExternalPort']:
|
|
||||||
changePortRequest = ''.join([ChangeRequest, '0004',
|
|
||||||
"00000002"])
|
|
||||||
log.debug("Do Test3")
|
|
||||||
ret = stun_test(s, changedIP, port, source_ip, source_port,
|
|
||||||
changePortRequest)
|
|
||||||
log.debug("Result: %s", ret)
|
|
||||||
if ret['Resp']:
|
|
||||||
typ = RestricNAT
|
|
||||||
else:
|
|
||||||
typ = RestricPortNAT
|
|
||||||
else:
|
|
||||||
typ = SymmetricNAT
|
|
||||||
return typ, ret
|
|
||||||
|
|
||||||
|
|
||||||
def get_ip_info(source_ip="0.0.0.0", source_port=54320, stun_host=None,
|
|
||||||
stun_port=3478):
|
|
||||||
socket.setdefaulttimeout(2)
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
s.bind((source_ip, source_port))
|
|
||||||
nat_type, nat = get_nat_type(s, source_ip, source_port,
|
|
||||||
stun_host=stun_host, stun_port=stun_port)
|
|
||||||
external_ip = nat['ExternalIP']
|
|
||||||
external_port = nat['ExternalPort']
|
|
||||||
s.close()
|
|
||||||
return (nat_type, external_ip, external_port)
|
|
|
@ -1,64 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import stun
|
|
||||||
|
|
||||||
|
|
||||||
def make_argument_parser():
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'-d', '--debug', action='store_true',
|
|
||||||
help='Enable debug logging'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-H', '--stun-host',
|
|
||||||
help='STUN host to use'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-P', '--stun-port', type=int,
|
|
||||||
default=stun.DEFAULTS['stun_port'],
|
|
||||||
help='STUN host port to use'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-i', '--source-ip',
|
|
||||||
default=stun.DEFAULTS['source_ip'],
|
|
||||||
help='network interface for client'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-p', '--source-port', type=int,
|
|
||||||
default=stun.DEFAULTS['source_port'],
|
|
||||||
help='port to listen on for client'
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument('--version', action='version', version=stun.__version__)
|
|
||||||
|
|
||||||
return parser
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
options = make_argument_parser().parse_args()
|
|
||||||
|
|
||||||
if options.debug:
|
|
||||||
logging.basicConfig()
|
|
||||||
stun.log.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
nat_type, external_ip, external_port = stun.get_ip_info(
|
|
||||||
source_ip=options.source_ip,
|
|
||||||
source_port=options.source_port,
|
|
||||||
stun_host=options.stun_host,
|
|
||||||
stun_port=options.stun_port
|
|
||||||
)
|
|
||||||
print('NAT Type:', nat_type)
|
|
||||||
print('External IP:', external_ip)
|
|
||||||
print('External Port:', external_port)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -130,7 +130,7 @@ class PostProcessor(object):
|
||||||
#forces mylar to use the executable that it was run with to run the extra script.
|
#forces mylar to use the executable that it was run with to run the extra script.
|
||||||
shell_cmd = sys.executable
|
shell_cmd = sys.executable
|
||||||
|
|
||||||
currentScriptName = shell_cmd + ' ' + str(mylar.CONFIG.PRE_SCRIPTS).decode("string_escape")
|
currentScriptName = shell_cmd + ' ' + str(mylar.CONFIG.PRE_SCRIPTS) #.decode("string_escape")
|
||||||
logger.fdebug("pre script detected...enabling: " + str(currentScriptName))
|
logger.fdebug("pre script detected...enabling: " + str(currentScriptName))
|
||||||
# generate a safe command line string to execute the script and provide all the parameters
|
# generate a safe command line string to execute the script and provide all the parameters
|
||||||
script_cmd = shlex.split(currentScriptName, posix=False) + [str(nzb_name), str(nzb_folder), str(seriesmetadata)]
|
script_cmd = shlex.split(currentScriptName, posix=False) + [str(nzb_name), str(nzb_folder), str(seriesmetadata)]
|
||||||
|
@ -171,7 +171,7 @@ class PostProcessor(object):
|
||||||
#forces mylar to use the executable that it was run with to run the extra script.
|
#forces mylar to use the executable that it was run with to run the extra script.
|
||||||
shell_cmd = sys.executable
|
shell_cmd = sys.executable
|
||||||
|
|
||||||
curScriptName = shell_cmd + ' ' + str(mylar.CONFIG.EXTRA_SCRIPTS).decode("string_escape")
|
curScriptName = shell_cmd + ' ' + str(mylar.CONFIG.EXTRA_SCRIPTS) #.decode("string_escape")
|
||||||
logger.fdebug("extra script detected...enabling: " + str(curScriptName))
|
logger.fdebug("extra script detected...enabling: " + str(curScriptName))
|
||||||
# generate a safe command line string to execute the script and provide all the parameters
|
# generate a safe command line string to execute the script and provide all the parameters
|
||||||
script_cmd = shlex.split(curScriptName) + [str(nzb_name), str(nzb_folder), str(filen), str(folderp), str(seriesmetadata)]
|
script_cmd = shlex.split(curScriptName) + [str(nzb_name), str(nzb_folder), str(filen), str(folderp), str(seriesmetadata)]
|
||||||
|
@ -368,7 +368,7 @@ class PostProcessor(object):
|
||||||
else:
|
else:
|
||||||
# if the SAB Directory option is enabled, let's use that folder name and append the jobname.
|
# if the SAB Directory option is enabled, let's use that folder name and append the jobname.
|
||||||
if all([mylar.CONFIG.SAB_TO_MYLAR, mylar.CONFIG.SAB_DIRECTORY is not None, mylar.CONFIG.SAB_DIRECTORY != 'None']):
|
if all([mylar.CONFIG.SAB_TO_MYLAR, mylar.CONFIG.SAB_DIRECTORY is not None, mylar.CONFIG.SAB_DIRECTORY != 'None']):
|
||||||
self.nzb_folder = os.path.join(mylar.CONFIG.SAB_DIRECTORY, self.nzb_name).encode(mylar.SYS_ENCODING)
|
self.nzb_folder = os.path.join(mylar.CONFIG.SAB_DIRECTORY, self.nzb_name) # .encode(mylar.SYS_ENCODING)
|
||||||
logger.fdebug('%s SABnzbd Download folder option enabled. Directory set to : %s' % (module, self.nzb_folder))
|
logger.fdebug('%s SABnzbd Download folder option enabled. Directory set to : %s' % (module, self.nzb_folder))
|
||||||
|
|
||||||
if mylar.USE_NZBGET==1:
|
if mylar.USE_NZBGET==1:
|
||||||
|
@ -380,7 +380,7 @@ class PostProcessor(object):
|
||||||
logger.fdebug('%s Manual Run Post-Processing enabled.' % module)
|
logger.fdebug('%s Manual Run Post-Processing enabled.' % module)
|
||||||
elif all([mylar.CONFIG.NZBGET_DIRECTORY is not None, mylar.CONFIG.NZBGET_DIRECTORY is not 'None']):
|
elif all([mylar.CONFIG.NZBGET_DIRECTORY is not None, mylar.CONFIG.NZBGET_DIRECTORY is not 'None']):
|
||||||
logger.fdebug('%s NZB name as passed from NZBGet: %s' % (module, self.nzb_name))
|
logger.fdebug('%s NZB name as passed from NZBGet: %s' % (module, self.nzb_name))
|
||||||
self.nzb_folder = os.path.join(mylar.CONFIG.NZBGET_DIRECTORY, self.nzb_name).encode(mylar.SYS_ENCODING)
|
self.nzb_folder = os.path.join(mylar.CONFIG.NZBGET_DIRECTORY, self.nzb_name) #.encode(mylar.SYS_ENCODING)
|
||||||
logger.fdebug('%s NZBGET Download folder option enabled. Directory set to : %s' % (module, self.nzb_folder))
|
logger.fdebug('%s NZBGET Download folder option enabled. Directory set to : %s' % (module, self.nzb_folder))
|
||||||
else:
|
else:
|
||||||
logger.fdebug('%s Now performing post-processing of %s sent from DDL' % (module, self.nzb_name))
|
logger.fdebug('%s Now performing post-processing of %s sent from DDL' % (module, self.nzb_name))
|
||||||
|
@ -2269,13 +2269,13 @@ class PostProcessor(object):
|
||||||
self._log("Publisher: %s" % publisher)
|
self._log("Publisher: %s" % publisher)
|
||||||
logger.fdebug('%s Publisher: %s' % (module, publisher))
|
logger.fdebug('%s Publisher: %s' % (module, publisher))
|
||||||
#we need to un-unicode this to make sure we can write the filenames properly for spec.chars
|
#we need to un-unicode this to make sure we can write the filenames properly for spec.chars
|
||||||
series = comicnzb['ComicName'].encode('ascii', 'ignore').strip()
|
series = comicnzb['ComicName'] #.encode('ascii', 'ignore').strip()
|
||||||
self._log("Series: %s" % series)
|
self._log("Series: %s" % series)
|
||||||
logger.fdebug('%s Series: %s' % (module, series))
|
logger.fdebug('%s Series: %s' % (module, series))
|
||||||
if comicnzb['AlternateFileName'] is None or comicnzb['AlternateFileName'] == 'None':
|
if comicnzb['AlternateFileName'] is None or comicnzb['AlternateFileName'] == 'None':
|
||||||
seriesfilename = series
|
seriesfilename = series
|
||||||
else:
|
else:
|
||||||
seriesfilename = comicnzb['AlternateFileName'].encode('ascii', 'ignore').strip()
|
seriesfilename = comicnzb['AlternateFileName'] #.encode('ascii', 'ignore').strip()
|
||||||
logger.fdebug('%s Alternate File Naming has been enabled for this series. Will rename series to : %s' % (module, seriesfilename))
|
logger.fdebug('%s Alternate File Naming has been enabled for this series. Will rename series to : %s' % (module, seriesfilename))
|
||||||
seriesyear = comicnzb['ComicYear']
|
seriesyear = comicnzb['ComicYear']
|
||||||
self._log("Year: %s" % seriesyear)
|
self._log("Year: %s" % seriesyear)
|
||||||
|
|
|
@ -1012,11 +1012,11 @@ def issuedigits(issnum):
|
||||||
#except:
|
#except:
|
||||||
# logger.fdebug('Unicode character detected: ' + issnum)
|
# logger.fdebug('Unicode character detected: ' + issnum)
|
||||||
#else: issnum.decode(mylar.SYS_ENCODING).decode('utf-8')
|
#else: issnum.decode(mylar.SYS_ENCODING).decode('utf-8')
|
||||||
if type(issnum) == str:
|
#if type(issnum) == str:
|
||||||
try:
|
# try:
|
||||||
issnum = issnum.decode('utf-8')
|
# issnum = issnum.decode('utf-8')
|
||||||
except:
|
# except:
|
||||||
issnum = issnum.decode('windows-1252')
|
# issnum = issnum.decode('windows-1252')
|
||||||
|
|
||||||
if type(issnum) == str:
|
if type(issnum) == str:
|
||||||
vals = {'\xbd':.5,'\xbc':.25,'\xbe':.75,'\u221e':9999999999,'\xe2':9999999999}
|
vals = {'\xbd':.5,'\xbc':.25,'\xbe':.75,'\u221e':9999999999,'\xe2':9999999999}
|
||||||
|
|
Loading…
Reference in New Issue