Python 3 fixes
This commit is contained in:
parent
a74f37c79e
commit
74bcf33591
|
@ -136,7 +136,7 @@ class AndroidObfuscationV2(AndroidObfuscation):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
count = 503
|
count = 503
|
||||||
password = 'Thomsun was here!'
|
password = b'Thomsun was here!'
|
||||||
|
|
||||||
def __init__(self, salt):
|
def __init__(self, salt):
|
||||||
key = self.password + salt
|
key = self.password + salt
|
||||||
|
@ -182,7 +182,7 @@ def get_serials1(path=STORAGE1):
|
||||||
obfuscation = AndroidObfuscation()
|
obfuscation = AndroidObfuscation()
|
||||||
|
|
||||||
def get_value(key):
|
def get_value(key):
|
||||||
encrypted_key = obfuscation.encrypt(key)
|
encrypted_key = obfuscation.encrypt(a2b_hex(key))
|
||||||
encrypted_value = storage.get(encrypted_key)
|
encrypted_value = storage.get(encrypted_key)
|
||||||
if encrypted_value:
|
if encrypted_value:
|
||||||
return obfuscation.decrypt(encrypted_value)
|
return obfuscation.decrypt(encrypted_value)
|
||||||
|
@ -217,15 +217,14 @@ def get_serials2(path=STORAGE2):
|
||||||
import sqlite3
|
import sqlite3
|
||||||
connection = sqlite3.connect(path)
|
connection = sqlite3.connect(path)
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute('''select userdata_value from userdata where userdata_key like '%/%token.device.deviceserialname%' ''')
|
cursor.execute('''select device_data_value from device_data where device_data_key like '%serial.number%' ''')
|
||||||
userdata_keys = cursor.fetchall()
|
device_data_keys = cursor.fetchall()
|
||||||
dsns = []
|
dsns = []
|
||||||
for userdata_row in userdata_keys:
|
for device_data_row in device_data_keys:
|
||||||
try:
|
try:
|
||||||
if userdata_row and userdata_row[0]:
|
if device_data_row and device_data_row[0]:
|
||||||
userdata_utf8 = userdata_row[0].encode('utf8')
|
if len(device_data_row[0]) > 0:
|
||||||
if len(userdata_utf8) > 0:
|
dsns.append(device_data_row[0])
|
||||||
dsns.append(userdata_utf8)
|
|
||||||
except:
|
except:
|
||||||
print("Error getting one of the device serial name keys")
|
print("Error getting one of the device serial name keys")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -238,9 +237,12 @@ def get_serials2(path=STORAGE2):
|
||||||
for userdata_row in userdata_keys:
|
for userdata_row in userdata_keys:
|
||||||
try:
|
try:
|
||||||
if userdata_row and userdata_row[0]:
|
if userdata_row and userdata_row[0]:
|
||||||
userdata_utf8 = userdata_row[0].encode('utf8')
|
if len(userdata_row[0]) > 0:
|
||||||
if len(userdata_utf8) > 0:
|
if ',' in userdata_row[0]:
|
||||||
tokens.append(userdata_utf8)
|
splits = userdata_row[0].split(',')
|
||||||
|
for split in splits:
|
||||||
|
tokens.append(split)
|
||||||
|
tokens.append(userdata_row[0])
|
||||||
except:
|
except:
|
||||||
print("Error getting one of the account token keys")
|
print("Error getting one of the account token keys")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -249,11 +251,10 @@ def get_serials2(path=STORAGE2):
|
||||||
|
|
||||||
serials = []
|
serials = []
|
||||||
for x in dsns:
|
for x in dsns:
|
||||||
serials.append(x)
|
|
||||||
for y in tokens:
|
for y in tokens:
|
||||||
serials.append('%s%s' % (x, y))
|
serials.append(x)
|
||||||
for y in tokens:
|
serials.append(y)
|
||||||
serials.append(y)
|
serials.append(x+y)
|
||||||
return serials
|
return serials
|
||||||
|
|
||||||
def get_serials(path=STORAGE):
|
def get_serials(path=STORAGE):
|
||||||
|
@ -275,7 +276,7 @@ def get_serials(path=STORAGE):
|
||||||
try :
|
try :
|
||||||
read = open(path, 'rb')
|
read = open(path, 'rb')
|
||||||
head = read.read(24)
|
head = read.read(24)
|
||||||
if head[:14] == 'ANDROID BACKUP':
|
if head[:14] == b'ANDROID BACKUP':
|
||||||
output = StringIO(zlib.decompress(read.read()))
|
output = StringIO(zlib.decompress(read.read()))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
@ -313,7 +314,7 @@ def getkey(outfile, inpath):
|
||||||
if len(keys) > 0:
|
if len(keys) > 0:
|
||||||
with open(outfile, 'w') as keyfileout:
|
with open(outfile, 'w') as keyfileout:
|
||||||
for key in keys:
|
for key in keys:
|
||||||
keyfileout.write(key)
|
keyfileout.write(b2a_hex(key))
|
||||||
keyfileout.write("\n")
|
keyfileout.write("\n")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
||||||
# Python 3, September 2020
|
# Python 3, September 2020
|
||||||
|
|
||||||
# Standard Python modules.
|
# Standard Python modules.
|
||||||
import os, traceback, json, binascii
|
import os, traceback, json, codecs
|
||||||
|
|
||||||
from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
|
from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
|
||||||
QGroupBox, QPushButton, QListWidget, QListWidgetItem,
|
QGroupBox, QPushButton, QListWidget, QListWidgetItem,
|
||||||
|
@ -378,7 +378,7 @@ class ManageKeysDialog(QDialog):
|
||||||
with open(fpath,'rb') as keyfile:
|
with open(fpath,'rb') as keyfile:
|
||||||
new_key_value = keyfile.read()
|
new_key_value = keyfile.read()
|
||||||
if self.binary_file:
|
if self.binary_file:
|
||||||
new_key_value = binascii.b2a_hex(new_key_value)
|
new_key_value = codecs.encode(new_key_value,'hex')
|
||||||
elif self.json_file:
|
elif self.json_file:
|
||||||
new_key_value = json.loads(new_key_value)
|
new_key_value = json.loads(new_key_value)
|
||||||
elif self.android_file:
|
elif self.android_file:
|
||||||
|
@ -433,18 +433,18 @@ class ManageKeysDialog(QDialog):
|
||||||
if filename:
|
if filename:
|
||||||
if self.binary_file:
|
if self.binary_file:
|
||||||
with open(filename, 'wb') as fname:
|
with open(filename, 'wb') as fname:
|
||||||
fname.write(binascii.a2b_hex(self.plugin_keys[keyname]))
|
fname.write(codecs.decode(self.plugin_keys[keyname],'hex'))
|
||||||
elif self.json_file:
|
elif self.json_file:
|
||||||
with open(filename, 'w') as fname:
|
with open(filename, 'w') as fname:
|
||||||
fname.write(json.dumps(self.plugin_keys[keyname]))
|
fname.write(json.dumps(self.plugin_keys[keyname]))
|
||||||
elif self.android_file:
|
elif self.android_file:
|
||||||
with open(filename, 'w') as fname:
|
with open(filename, 'w') as fname:
|
||||||
for key in self.plugin_keys[keyname]:
|
for key in self.plugin_keys[keyname]:
|
||||||
fname.write(key.decode('utf-8'))
|
fname.write(key)
|
||||||
fname.write('\n')
|
fname.write('\n')
|
||||||
else:
|
else:
|
||||||
with open(filename, 'w') as fname:
|
with open(filename, 'w') as fname:
|
||||||
fname.write(self.plugin_keys[keyname].decode('utf-8'))
|
fname.write(self.plugin_keys[keyname])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ class AddEReaderDialog(QDialog):
|
||||||
@property
|
@property
|
||||||
def key_value(self):
|
def key_value(self):
|
||||||
from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key
|
from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key
|
||||||
return binascii.b2a_hex(generate_ereader_key(self.user_name, self.cc_number))
|
return codecs.encode(generate_ereader_key(self.user_name, self.cc_number),'hex')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_name(self):
|
def user_name(self):
|
||||||
|
@ -755,7 +755,7 @@ class AddAdeptDialog(QDialog):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def key_value(self):
|
def key_value(self):
|
||||||
return binascii.b2a_hex(self.default_key)
|
return codecs.encode(self.default_key,'hex')
|
||||||
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
|
|
|
@ -542,7 +542,7 @@ def usage():
|
||||||
print(" It's enough to enter the last 8 digits of the credit card number")
|
print(" It's enough to enter the last 8 digits of the credit card number")
|
||||||
return
|
return
|
||||||
|
|
||||||
def getuser_key(name, cc):
|
def getuser_key(name,cc):
|
||||||
newname = "".join(c for c in name.lower() if c >= 'a' and c <= 'z' or c >= '0' and c <= '9')
|
newname = "".join(c for c in name.lower() if c >= 'a' and c <= 'z' or c >= '0' and c <= '9')
|
||||||
cc = cc.replace(" ","")
|
cc = cc.replace(" ","")
|
||||||
return struct.pack('>LL', binascii.crc32(bytes(newname.encode('utf-8'))) & 0xffffffff, binascii.crc32(bytes(cc[-8:].encode('utf-8'))) & 0xffffffff)
|
return struct.pack('>LL', binascii.crc32(bytes(newname.encode('utf-8'))) & 0xffffffff, binascii.crc32(bytes(cc[-8:].encode('utf-8'))) & 0xffffffff)
|
||||||
|
@ -580,9 +580,9 @@ def cli_main():
|
||||||
elif len(args)==4:
|
elif len(args)==4:
|
||||||
infile, outpath, name, cc = args
|
infile, outpath, name, cc = args
|
||||||
|
|
||||||
print(binascii.b2a_hex(getuser_key(name, cc)))
|
print(binascii.b2a_hex(getuser_key(name,cc)))
|
||||||
|
|
||||||
return decryptBook(infile, outpath, make_pmlz, getuser_key(name, cc))
|
return decryptBook(infile, outpath, make_pmlz, getuser_key(name,cc))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -203,6 +203,7 @@ def _load_crypto_libcrypto():
|
||||||
def _load_crypto_pycrypto():
|
def _load_crypto_pycrypto():
|
||||||
from Crypto.Cipher import AES as _AES
|
from Crypto.Cipher import AES as _AES
|
||||||
from Crypto.PublicKey import RSA as _RSA
|
from Crypto.PublicKey import RSA as _RSA
|
||||||
|
from Crypto.Cipher import PKCS1_v1_5 as _PKCS1_v1_5
|
||||||
|
|
||||||
# ASN.1 parsing code from tlslite
|
# ASN.1 parsing code from tlslite
|
||||||
class ASN1Error(Exception):
|
class ASN1Error(Exception):
|
||||||
|
@ -294,14 +295,14 @@ def _load_crypto_pycrypto():
|
||||||
|
|
||||||
class AES(object):
|
class AES(object):
|
||||||
def __init__(self, key):
|
def __init__(self, key):
|
||||||
self._aes = _AES.new(key, _AES.MODE_CBC, '\x00'*16)
|
self._aes = _AES.new(key, _AES.MODE_CBC, b'\x00'*16)
|
||||||
|
|
||||||
def decrypt(self, data):
|
def decrypt(self, data):
|
||||||
return self._aes.decrypt(data)
|
return self._aes.decrypt(data)
|
||||||
|
|
||||||
class RSA(object):
|
class RSA(object):
|
||||||
def __init__(self, der):
|
def __init__(self, der):
|
||||||
key = ASN1Parser([ord(x) for x in der])
|
key = ASN1Parser([x for x in der])
|
||||||
key = [key.getChild(x).value for x in range(1, 4)]
|
key = [key.getChild(x).value for x in range(1, 4)]
|
||||||
key = [self.bytesToNumber(v) for v in key]
|
key = [self.bytesToNumber(v) for v in key]
|
||||||
self._rsa = _RSA.construct(key)
|
self._rsa = _RSA.construct(key)
|
||||||
|
@ -313,7 +314,7 @@ def _load_crypto_pycrypto():
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def decrypt(self, data):
|
def decrypt(self, data):
|
||||||
return self._rsa.decrypt(data)
|
return _PKCS1_v1_5.new(self._rsa).decrypt(data, 172)
|
||||||
|
|
||||||
return (AES, RSA)
|
return (AES, RSA)
|
||||||
|
|
||||||
|
@ -410,11 +411,14 @@ def decryptBook(userkey, inpath, outpath):
|
||||||
return 1
|
return 1
|
||||||
bookkey = rsa.decrypt(codecs.decode(bookkey.encode('ascii'), 'base64'))
|
bookkey = rsa.decrypt(codecs.decode(bookkey.encode('ascii'), 'base64'))
|
||||||
# Padded as per RSAES-PKCS1-v1_5
|
# Padded as per RSAES-PKCS1-v1_5
|
||||||
if bookkey[-17] != '\x00' and bookkey[-17] != 0:
|
if len(bookkey) != 16:
|
||||||
print("Could not decrypt {0:s}. Wrong key".format(os.path.basename(inpath)))
|
if bookkey[-17] != '\x00' and bookkey[-17] != 0:
|
||||||
return 2
|
print("Could not decrypt {0:s}. Wrong key".format(os.path.basename(inpath)))
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
bookkey = bookkey[-16:]
|
||||||
encryption = inf.read('META-INF/encryption.xml')
|
encryption = inf.read('META-INF/encryption.xml')
|
||||||
decryptor = Decryptor(bookkey[-16:], encryption)
|
decryptor = Decryptor(bookkey, encryption)
|
||||||
kwds = dict(compression=ZIP_DEFLATED, allowZip64=False)
|
kwds = dict(compression=ZIP_DEFLATED, allowZip64=False)
|
||||||
with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf:
|
with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf:
|
||||||
zi = ZipInfo('mimetype')
|
zi = ZipInfo('mimetype')
|
||||||
|
@ -475,9 +479,9 @@ def cli_main():
|
||||||
def gui_main():
|
def gui_main():
|
||||||
try:
|
try:
|
||||||
import tkinter
|
import tkinter
|
||||||
import tkinter_constants
|
import tkinter.constants
|
||||||
import tkinter_filedialog
|
import tkinter.filedialog
|
||||||
import tkinter_messagebox
|
import tkinter.messagebox
|
||||||
import traceback
|
import traceback
|
||||||
except:
|
except:
|
||||||
return cli_main()
|
return cli_main()
|
||||||
|
@ -486,10 +490,10 @@ def gui_main():
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
tkinter.Frame.__init__(self, root, border=5)
|
tkinter.Frame.__init__(self, root, border=5)
|
||||||
self.status = tkinter.Label(self, text="Select files for decryption")
|
self.status = tkinter.Label(self, text="Select files for decryption")
|
||||||
self.status.pack(fill=tkinter_constants.X, expand=1)
|
self.status.pack(fill=tkinter.constants.X, expand=1)
|
||||||
body = tkinter.Frame(self)
|
body = tkinter.Frame(self)
|
||||||
body.pack(fill=tkinter_constants.X, expand=1)
|
body.pack(fill=tkinter.constants.X, expand=1)
|
||||||
sticky = tkinter_constants.E + tkinter_constants.W
|
sticky = tkinter.constants.E + tkinter.constants.W
|
||||||
body.grid_columnconfigure(1, weight=2)
|
body.grid_columnconfigure(1, weight=2)
|
||||||
tkinter.Label(body, text="Key file").grid(row=0)
|
tkinter.Label(body, text="Key file").grid(row=0)
|
||||||
self.keypath = tkinter.Entry(body, width=30)
|
self.keypath = tkinter.Entry(body, width=30)
|
||||||
|
@ -512,41 +516,41 @@ def gui_main():
|
||||||
buttons.pack()
|
buttons.pack()
|
||||||
botton = tkinter.Button(
|
botton = tkinter.Button(
|
||||||
buttons, text="Decrypt", width=10, command=self.decrypt)
|
buttons, text="Decrypt", width=10, command=self.decrypt)
|
||||||
botton.pack(side=tkinter_constants.LEFT)
|
botton.pack(side=tkinter.constants.LEFT)
|
||||||
tkinter.Frame(buttons, width=10).pack(side=tkinter_constants.LEFT)
|
tkinter.Frame(buttons, width=10).pack(side=tkinter.constants.LEFT)
|
||||||
button = tkinter.Button(
|
button = tkinter.Button(
|
||||||
buttons, text="Quit", width=10, command=self.quit)
|
buttons, text="Quit", width=10, command=self.quit)
|
||||||
button.pack(side=tkinter_constants.RIGHT)
|
button.pack(side=tkinter.constants.RIGHT)
|
||||||
|
|
||||||
def get_keypath(self):
|
def get_keypath(self):
|
||||||
keypath = tkinter_filedialog.askopenfilename(
|
keypath = tkinter.filedialog.askopenfilename(
|
||||||
parent=None, title="Select Adobe Adept \'.der\' key file",
|
parent=None, title="Select Adobe Adept \'.der\' key file",
|
||||||
defaultextension=".der",
|
defaultextension=".der",
|
||||||
filetypes=[('Adobe Adept DER-encoded files', '.der'),
|
filetypes=[('Adobe Adept DER-encoded files', '.der'),
|
||||||
('All Files', '.*')])
|
('All Files', '.*')])
|
||||||
if keypath:
|
if keypath:
|
||||||
keypath = os.path.normpath(keypath)
|
keypath = os.path.normpath(keypath)
|
||||||
self.keypath.delete(0, tkinter_constants.END)
|
self.keypath.delete(0, tkinter.constants.END)
|
||||||
self.keypath.insert(0, keypath)
|
self.keypath.insert(0, keypath)
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_inpath(self):
|
def get_inpath(self):
|
||||||
inpath = tkinter_filedialog.askopenfilename(
|
inpath = tkinter.filedialog.askopenfilename(
|
||||||
parent=None, title="Select ADEPT-encrypted ePub file to decrypt",
|
parent=None, title="Select ADEPT-encrypted ePub file to decrypt",
|
||||||
defaultextension=".epub", filetypes=[('ePub files', '.epub')])
|
defaultextension=".epub", filetypes=[('ePub files', '.epub')])
|
||||||
if inpath:
|
if inpath:
|
||||||
inpath = os.path.normpath(inpath)
|
inpath = os.path.normpath(inpath)
|
||||||
self.inpath.delete(0, tkinter_constants.END)
|
self.inpath.delete(0, tkinter.constants.END)
|
||||||
self.inpath.insert(0, inpath)
|
self.inpath.insert(0, inpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_outpath(self):
|
def get_outpath(self):
|
||||||
outpath = tkinter_filedialog.asksaveasfilename(
|
outpath = tkinter.filedialog.asksaveasfilename(
|
||||||
parent=None, title="Select unencrypted ePub file to produce",
|
parent=None, title="Select unencrypted ePub file to produce",
|
||||||
defaultextension=".epub", filetypes=[('ePub files', '.epub')])
|
defaultextension=".epub", filetypes=[('ePub files', '.epub')])
|
||||||
if outpath:
|
if outpath:
|
||||||
outpath = os.path.normpath(outpath)
|
outpath = os.path.normpath(outpath)
|
||||||
self.outpath.delete(0, tkinter_constants.END)
|
self.outpath.delete(0, tkinter.constants.END)
|
||||||
self.outpath.insert(0, outpath)
|
self.outpath.insert(0, outpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -576,13 +580,13 @@ def gui_main():
|
||||||
if decrypt_status == 0:
|
if decrypt_status == 0:
|
||||||
self.status['text'] = "File successfully decrypted"
|
self.status['text'] = "File successfully decrypted"
|
||||||
else:
|
else:
|
||||||
self.status['text'] = "The was an error decrypting the file."
|
self.status['text'] = "There was an error decrypting the file."
|
||||||
|
|
||||||
root = tkinter.Tk()
|
root = tkinter.Tk()
|
||||||
root.title("Adobe Adept ePub Decrypter v.{0}".format(__version__))
|
root.title("Adobe Adept ePub Decrypter v.{0}".format(__version__))
|
||||||
root.resizable(True, False)
|
root.resizable(True, False)
|
||||||
root.minsize(300, 0)
|
root.minsize(300, 0)
|
||||||
DecryptionDialog(root).pack(fill=tkinter_constants.X, expand=1)
|
DecryptionDialog(root).pack(fill=tkinter.constants.X, expand=1)
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
||||||
|
|
||||||
# Standard Python modules.
|
# Standard Python modules.
|
||||||
import os, sys, re, hashlib
|
import os, sys, re, hashlib
|
||||||
import json
|
import codecs, json
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from calibre.utils.config import dynamic, config_dir, JSONConfig
|
from calibre.utils.config import dynamic, config_dir, JSONConfig
|
||||||
|
@ -116,7 +116,7 @@ def convertprefs(always = False):
|
||||||
name, cc = keystring.split(',')
|
name, cc = keystring.split(',')
|
||||||
# Generate eReader user key from name and credit card number.
|
# Generate eReader user key from name and credit card number.
|
||||||
keyname = "{0}_{1}".format(name.strip(),cc.strip()[-4:])
|
keyname = "{0}_{1}".format(name.strip(),cc.strip()[-4:])
|
||||||
keyvalue = getuser_key(name,cc).encode('hex')
|
keyvalue = codecs.encode(getuser_key(name,cc),'hex')
|
||||||
userkeys.append([keyname,keyvalue])
|
userkeys.append([keyname,keyvalue])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -146,7 +146,7 @@ def convertprefs(always = False):
|
||||||
key = os.path.splitext(filename)[0]
|
key = os.path.splitext(filename)[0]
|
||||||
value = open(fpath, 'rb').read()
|
value = open(fpath, 'rb').read()
|
||||||
if encoding is not None:
|
if encoding is not None:
|
||||||
value = value.encode(encoding)
|
value = codecs.encode(value,encoding)
|
||||||
userkeys.append([key,value])
|
userkeys.append([key,value])
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
|
@ -286,8 +286,8 @@ class ZipInfo (object):
|
||||||
# This is used to ensure paths in generated ZIP files always use
|
# This is used to ensure paths in generated ZIP files always use
|
||||||
# forward slashes as the directory separator, as required by the
|
# forward slashes as the directory separator, as required by the
|
||||||
# ZIP format specification.
|
# ZIP format specification.
|
||||||
if os.sep != "/" and os.sep in filename:
|
if os.sep != "/" and os.sep.encode('utf-8') in filename:
|
||||||
filename = filename.replace(os.sep, "/")
|
filename = filename.replace(os.sep.encode('utf-8'), b"/")
|
||||||
|
|
||||||
self.filename = filename # Normalized file name
|
self.filename = filename # Normalized file name
|
||||||
self.date_time = date_time # year, month, day, hour, min, sec
|
self.date_time = date_time # year, month, day, hour, min, sec
|
||||||
|
|
Loading…
Reference in New Issue