def _deleteSession(self, filePath): result = QMessageBox.information(gVar.app.activeWindow(), _('Delete Session'), _('Are you sure you want to delete session \'%s\'?') % QFileInfo(filePath).completeBaseName(), QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: QFile.remove(filePath)
def deleteFile(self, path, name): file = QFile(path + name + ".tmp") print(file.fileName()) if file.exists(): print(file.remove()) file.setFileName(path + name + ".tmp.cfg") if file.exists(): print(file.remove())
def backupSavedSessions(self): if not QFile.exists(self._lastActiveSessionPath): return if QFile.exists(self._firstBackupSession): QFile.remove(self._secondBackupSession) QFile.copy(self._firstBackupSession, self._secondBackupSession) QFile.remove(self._firstBackupSession) QFile.copy(self._lastActiveSessionPath, self._firstBackupSession)
def save (self,filename = None): print ("sauvegarde") progress = QProgressDialog () progress.setWindowModality(QtCore.Qt.WindowModal) progress.setLabelText("Sauvegarde") progress.setMaximum(len(self.getWarriorList())+1) #db_name = self.database.database.databaseName() if filename == None : filename = os.path.join(Config().instance.path_to_sqlite(),self.settings.value("global/current_database")) try : print ('current filename', filename) # backup filename_bkp = filename+"_"+QtCore.QDateTime.currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") QFile.copy(filename,filename_bkp) if QFile.remove(filename) == False : qWarning("echec suppression ") else: qWarning("reussite suppression %s"% filename) except OSError : qWarning("echec suppression ") result = QFile.copy(Config().instance.model_database(),filename) if result == False : print("echec de la copy ",Config().instance.model_database(),filename) return else: print("copy du model reussit") database = DatabaseManager(filename,True) database.createConnection() database.setVerbose(True) for faction in self.factions.values() : attribs = faction.getDictAttributes () database.insert("gm_faction",attribs) for empire in faction.empires.values(): attribs = empire.getDictAttributes () database.insert("gm_empire",attribs) for kingdom in empire.kingdoms.values(): attribs = kingdom.getDictAttributes () database.insert("gm_kingdom",attribs) for temple in kingdom.temples: attribs = temple.getDictAttributes () database.insert("gm_temple",attribs) for groupe in kingdom.groupes.values(): attribs = groupe.getDictAttributes () database.insert("gm_groupe",attribs) for sub_groupe in groupe.sub_groupes: attribs = sub_groupe.getDictAttributes () database.insert("gm_groupe",attribs) for perso in sub_groupe.warriors.values(): attribs = perso.getDictAttributes () database.insert("gm_perso",attribs) for perso in groupe.warriors.values(): attribs = perso.getDictAttributes () database.insert("gm_perso",attribs) progress.setValue(progress.value()+1)
def removeRecursively(self, filePath): ''' @param: filePath QString ''' fileInfo = QFileInfo(filePath) if not fileInfo.exists() and not fileInfo.isSymLink(): return if fileInfo.isDir() and not fileInfo.isSymLink(): dir_ = QDir(filePath) dir_ = dir_.canonicalPath() if dir_.isRoot() or dir_.path() == QDir.home().canonicalPath(): print('CRITICAL: Attempt to remove root/home directory', dir_) return False fileNames = dir_.entryList(QDir.Files | QDir.Dirs | QDir.NoDotAndDotDot | QDir.Hidden | QDir.System) for fileName in fileNames: if not self.removeRecursively(filePath + '/' + fileName): return False if not QDir.root().rmdir(dir_.path()): return False elif not QFile.remove(filePath): return False return True
class HttpsDownloader(QObject): # pyqtSignal downloadProgress = pyqtSignal("qint64", "qint64", "qint64", arguments=["receiver", "total", "timeStamp"]) # 初始化函数 def __init__(self, parent=None): super(HttpsDownloader, self).__init__(parent) self._manager = QNetworkAccessManager(self) self._attributes = DownloaderAttributes( DownloaderAttributes.UrlType.Https, self) self._tmpFile = QFile(self) self._configFile = QFile(self) self._reply = None # 析构函数 def __del__(self): # 这些析构函数会报错 # if self._tmpFile.isOpen(): # self._tmpFile.close() # if self._configFile.isOpen(): # self._configFile.close() # if self._reply: # self._reply.deleteLater() pass # 类的属性,提供给qml使用# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # attributes# # # # # # # # # @pyqtProperty(DownloaderAttributes) def attributes(self): return self._attributes # 判断文件是否在此目录 # path:文件所在路径 # filename:文件名(不带路径,带后缀名) def isFileExist(self, path, filename): dir = QDir(path) return filename in dir.entryList() # 任务状态的改变,用于用户操作或者出现异常情况时设置 # 通过UI通知用户,不弹窗 def changeState(self, state): self.attributes.setState(state) # 这里判断目录是否存在,不存在则创建 def isDirExist(self, fullPath): dir = QDir(fullPath) if dir.exists(): return True else: return dir.mkpath(fullPath) # 打开配置文件 def _openConfig(self): config = self.attributes.fileName + '.tmp.cfg' self._configFile.setFileName(self.attributes.path + config) self._configFile.open(QFile.ReadWrite) # 打开临时文件,用于保存下载信息 # 在这里重置文件大小 def _openTemp(self): tempname = self.attributes.fileName + '.tmp' if self._tmpFile.isOpen(): self._tmpFile.close() self._tmpFile.setFileName(self.attributes.path + tempname) self._tmpFile.open(QFile.Append) self._tmpFile.seek(self.attributes.preProgress) # 保存config def _saveConfig(self): if not self._configFile.isOpen(): return False info = self.attributes.toJson() self._configFile.resize(0) self._configFile.seek(0) self._configFile.write(QJsonDocument(info).toJson()) self._configFile.flush() return True # 读取config def _loadConfig(self): self._configFile.seek(0) cfg = self._configFile.readAll() if len(cfg) <= 0: return False j = QJsonDocument.fromJson(cfg).object() self.attributes.fromJson(j) return True # 开始下载文件 def startDownload(self, isPause): # 这里区分批量下载和单个文件下载 if self.attributes.totalFile == 1: # 这里不需要重新计算文件名,因为在UI已经确认过了,这里如果文件名相同则会是 # 继续下载,所以不存在会文件名相同 # 单个文件下载则任务名和文件名同名 self.attributes.taskName = self.attributes.fileName # 打开配置文件并保存,这一步放在设置文件名后执行 self._openConfig() if self._loadConfig(): # 存在历史纪录 pass else: self._saveConfig() self._openTemp() if not isPause: # 如果不是暂停,则下载 self._download_signal(self.attributes.url) else: self.changeState(DownloaderAttributes.States.pause) else: self.attributes.path = self.attributes.path[:-1] + self.attributes.fileName # 生成目录 self.isDirExist(self.attributes.path) # 重置文件名,用于生成配置文件而已 if len(self.attributes.fileName.split('/')) >= 2: self.attributes.fileName = self.attributes.checkFileName( self.attributes.fileName.split('/')[-2], self.attributes.path) else: self.attributes.fileName = self.attributes.checkFileName( self.attributes.fileName, self.attributes.path) # 多个文件下载则是文件夹的名字 self.attributes.taskName = self.attributes.fileName # 打开配置文件并保存,这一步放在设置文件名后执行 self._openConfig() if self._loadConfig(): # 存在历史纪录 pass else: self._saveConfig() if not isPause: # 如果不是暂停,则下载 # 设置为另一个接口主要的意图在于,多个文件下载完都会调用一次该接口 self._download_mult() else: self.changeState(DownloaderAttributes.States.pause) # 下载单个文件 # total用来表示文件大小,这样的优点在于预加载就可以显示文件大小的信息 def _download_signal(self, url): request = QNetworkRequest() request.setRawHeader( str("Range").encode(), str("bytes=" + str(self.attributes.preProgress) + "-").encode()) # 设置自动重定向,之前自己实现的链接跳转就可以去掉了 request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True) request.setUrl(QUrl(url)) self.changeState(DownloaderAttributes.States.downloading) self._reply = self._manager.get(request) self._reply.downloadProgress.connect(self.writeFile) self._reply.finished.connect(self.downloadError) return True # 下载多个文件 def _download_mult(self): # 任务开始前先重置下载进度 name = self.attributes.url.split('/')[-1].split('.') newNum = str(int(name[0]) + self.attributes.finishFile).zfill( len(name[0])) newNum = newNum + "." + name[1] self.attributes.fileName = newNum url = self.attributes.url[:self.attributes.url.rfind('/') + 1] + newNum self._openTemp() print(url) self._download_signal(url) pass # 把数据写入文件的指令 def _writeFile(self, data): self._tmpFile.seek(self.attributes.curProgress) b = self._tmpFile.writeData(data) return b # 槽函数 # 用于任务终止时输出错误信息,下载完成也会触发 @pyqtSlot() def downloadError(self): print("IOError", self._reply.errorString()) print("NetworkError", self._reply.error()) logging.info("IOError" + self._reply.errorString()) # 槽函数 # 把下载的内容写入文件 # receive:已接收的字节数 # total:文件总大小 @pyqtSlot("qint64", "qint64") def writeFile(self, receive, total): # print("receive",receive) # print("total",total) # print(self._reply.error()) if total <= 0: # -1有可能是下载错误 if receive <= 0: self.changeState(DownloaderAttributes.States.networkError) # 这里不打算中断网络链接,经过观察再决定这里是否中断 return else: # 这种情况是total返回-1,但是实际上是有下载的 self.changeState(DownloaderAttributes.States.totalLessThanZero) # 这里是刚开始下载的时候,total默认是0,设置下载的文件大小 if self.attributes.total != total: self.attributes.total = total + self.attributes.preProgress if self._tmpFile.isOpen(): if self._tmpFile.size() < total: self._tmpFile.resize(total) else: self.changeState(DownloaderAttributes.States.fileOpenError) return # 这里是暂停续传部分,因为更改了暂停机制,在暂停前取消信号连接, # 所以这里基本不存在触发的情况 if self.attributes._state == DownloaderAttributes.States.pause: # 暂停触发,不处理后面接受到的字节数 if self._reply.isRunning(): # 如果reply还没有关闭则关闭下载通道 # 这个在软件重开续传和预读头文件的时候预防下载通道还没关闭的情况 self._reply.downloadProgress.disconnect(self.writeFile) self._reply.abort() return elif not self._reply.isOpen(): if self.attributes.curProgress == self.attributes.total: # 其实这里已经排除abort触发的情况因为在abort之前已经断开信号连接 # 这里的条件判断以及输出是用于日志输出 print("abort 触发") pass else: # 如果不是因为暂停而关闭reply的通道的情况则需要通报用户下载失败 self.changeState(DownloaderAttributes.States.networkError) return else: # 正常情况 data = self._reply.readAll() if len(data) == 0: # 没有数据读取 if self._reply.error() == QNetworkReply.NoError: self.success() else: self.changeState(DownloaderAttributes.States.networkError) return if self._tmpFile.writeData(data) <= 0: self.changeState(DownloaderAttributes.States.fileWriteError) return # 获取时间戳,因为我不知道qml如何获取,然后发射信号给qml更新界面 self._tmpFile.flush() self.attributes.curTime = int(time.time()) self.attributes.curProgress = receive + self.attributes.preProgress self._saveConfig() # 下载完成的处理,不使用finish是因为那个信号啥都会触发 if self.attributes.curProgress == self.attributes.total: self.success() # 槽函数 # 暂停/继续下载 @pyqtSlot(bool) def pauseDown(self): if self.attributes._state == DownloaderAttributes.States.downloading: # 正在下载,应该处理暂停 self.changeState(DownloaderAttributes.States.pause) if self._reply != None and self._reply.isRunning(): self._reply.downloadProgress.disconnect(self.writeFile) self._reply.abort() self.attributes.preProgress = self.attributes.curProgress else: self.changeState(DownloaderAttributes.States.downloading) if self.attributes.totalFile > 1: self._download_mult() else: self._download_signal(self.attributes.url) # 槽函数 # 下载成功,设置标志位finish为true,然后停止下载. @pyqtSlot() def success(self): self.attributes.completedOne() # 虽然下载完成,但是还是需要关闭通道 # 这里解决了只能下载第一个文件的情况,也解决了下载完成所有任务后,多下载两个文件 # 貌似是下载文件时多次触发success,所以要断开信号和关闭下载通道 self._reply.downloadProgress.disconnect(self.writeFile) self._reply.abort() name = self.attributes.checkFileName(self.attributes.fileName, self.attributes.path) self._tmpFile.rename(self.attributes.path + name) self._tmpFile.close() # 下载完所有文件,同样适用于下载单个文件 if self.attributes.finishFile == self.attributes.totalFile: pass else: # 这个情况只有下载多个文件的时候才会出现 # 重置多个文件下载时的参数 self.attributes.downloadParamReset() self._saveConfig() self._download_mult() return self._configFile.remove() self.changeState(DownloaderAttributes.States.finish) # 删除这次任务,当然,这里只是关闭文件而已 # 正真删除操作在setting类 # 因为只有正在下载的任务有这个类 # 重构后,可能在这里实现文件的删除操作 def deleteFile(self): self._tmpFile.close() self._configFile.close()
class UploadWorker(QObject): readyForNext = pyqtSignal(int) uploadProgress = pyqtSignal(int, int, int) uploaded = pyqtSignal(int) updated = pyqtSignal(int) skipped = pyqtSignal(int) failed = pyqtSignal(int, str) aborted = pyqtSignal(str) def __init__(self, index, reupload, db, logger): QObject.__init__(self) self.index = index self.reupload = reupload self.db = db self.logger = logger self.api_key = prefs['api_key'] self.reply = None self.canceled = False self.retries = 0 def start(self): self.network = QNetworkAccessManager() self.network.authenticationRequired.connect(self.auth) self.readyForNext.emit(self.index) def cancel(self): self.canceled = True if self.reply: self.reply.abort() def sync(self, book_id, file_path): self.book_id = book_id self.file_path = file_path self.check() def auth(self, reply, authenticator): if not authenticator.user(): authenticator.setUser(self.api_key) authenticator.setPassword('') def check(self): self.digest = None identifiers = self.db.get_proxy_metadata(self.book_id).identifiers if identifiers.get('bookfusion'): self.is_search_req = False self.req = api.build_request('/uploads/' + identifiers['bookfusion']) self.log_info('Upload check: bookfusion={}'.format( identifiers['bookfusion'])) elif identifiers.get('isbn'): self.is_search_req = True self.req = api.build_request('/uploads', {'isbn': identifiers['isbn']}) self.log_info('Upload check: isbn={}'.format(identifiers['isbn'])) else: self.calculate_digest() self.is_search_req = False self.req = api.build_request('/uploads/' + self.digest) self.log_info('Upload check: digest={}'.format(self.digest)) self.reply = self.network.get(self.req) self.reply.finished.connect(self.complete_check) def complete_check(self): abort = False skip = False update = False result = None error = self.reply.error() if error == QNetworkReply.AuthenticationRequiredError: abort = True self.aborted.emit('Invalid API key.') self.log_info('Upload check: AuthenticationRequiredError') elif error == QNetworkReply.NoError: resp = self.reply.readAll() self.log_info('Upload check response: {}'.format(resp)) if self.is_search_req: results = json.loads(resp.data()) if len(results) > 0: result = results[0] else: result = json.loads(resp.data()) if result is not None: self.set_bookfusion_id(result['id']) update = True elif error == QNetworkReply.ContentNotFoundError: self.log_info('Upload check: ContentNotFoundError') elif error == QNetworkReply.InternalServerError: self.log_info('Upload check: InternalServerError') resp = self.reply.readAll() self.log_info('Upload check response: {}'.format(resp)) elif error == QNetworkReply.UnknownServerError: self.log_info('Upload check: UnknownServerError') resp = self.reply.readAll() self.log_info('Upload check response: {}'.format(resp)) elif error == QNetworkReply.OperationCanceledError: abort = True self.log_info('Upload check: OperationCanceledError') else: abort = True self.aborted.emit('Error {}.'.format(error)) self.log_info('Upload check error: {}'.format(error)) self.reply.deleteLater() self.reply = None if not abort: if skip: self.readyForNext.emit(self.index) else: self.metadata_digest = self.get_metadata_digest() if not result is None and self.metadata_digest == result[ 'calibre_metadata_digest'] and not self.reupload: self.skipped.emit(self.book_id) self.readyForNext.emit(self.index) else: if update: self.update() else: self.init_upload() def init_upload(self): self.calculate_digest() self.req = api.build_request('/uploads/init') self.req_body = QHttpMultiPart(QHttpMultiPart.FormDataType) self.req_body.append( self.build_req_part('filename', path.basename(self.file_path))) self.req_body.append(self.build_req_part('digest', self.digest)) self.reply = self.network.post(self.req, self.req_body) self.reply.finished.connect(self.complete_init_upload) def complete_init_upload(self): resp, retry, abort = self.complete_req('Upload init', return_json=True) if retry: self.init_upload() return if abort: return if resp is not None: self.upload_url = resp['url'] self.upload_params = resp['params'] self.upload() else: self.readyForNext.emit(self.index) def upload(self): self.file = QFile(self.file_path) self.file.open(QIODevice.ReadOnly) self.req = QNetworkRequest(QUrl(self.upload_url)) self.req_body = QHttpMultiPart(QHttpMultiPart.FormDataType) for key, value in self.upload_params.items(): self.log_info('{}={}'.format(key, value)) self.req_body.append(self.build_req_part(key, value)) self.req_body.append(self.build_req_part('file', self.file)) self.reply = self.network.post(self.req, self.req_body) self.reply.finished.connect(self.complete_upload) self.reply.uploadProgress.connect(self.upload_progress) def complete_upload(self): if self.file: self.file.close() resp, retry, abort = self.complete_req('Upload') if retry: self.upload() return if abort: return if resp is not None: self.finalize_upload() else: self.readyForNext.emit(self.index) def finalize_upload(self): self.req = api.build_request('/uploads/finalize') self.req_body = QHttpMultiPart(QHttpMultiPart.FormDataType) self.req_body.append( self.build_req_part('key', self.upload_params['key'])) self.req_body.append(self.build_req_part('digest', self.digest)) self.append_metadata_req_parts() self.reply = self.network.post(self.req, self.req_body) self.reply.finished.connect(self.complete_finalize_upload) def complete_finalize_upload(self): self.clean_metadata_req() resp, retry, abort = self.complete_req('Upload finalize', return_json=True) if retry: self.finalize_upload() return if abort: return if resp is not None: self.set_bookfusion_id(resp['id']) self.uploaded.emit(self.book_id) self.readyForNext.emit(self.index) def update(self): if not prefs['update_metadata'] and not self.reupload: self.skipped.emit(self.book_id) self.readyForNext.emit(self.index) return identifiers = self.db.get_proxy_metadata(self.book_id).identifiers if not identifiers.get('bookfusion') and not self.reupload: self.skipped.emit(self.book_id) self.readyForNext.emit(self.index) return self.req = api.build_request('/uploads/' + identifiers['bookfusion']) self.req_body = QHttpMultiPart(QHttpMultiPart.FormDataType) if self.reupload: self.file = QFile(self.file_path) self.file.open(QIODevice.ReadOnly) self.req_body.append(self.build_req_part('file', self.file)) self.append_metadata_req_parts() self.reply = self.network.put(self.req, self.req_body) self.reply.finished.connect(self.complete_update) def complete_update(self): self.clean_metadata_req() resp, retry, abort = self.complete_req('Update') if retry: self.update() return if abort: return if resp is not None: self.updated.emit(self.book_id) self.readyForNext.emit(self.index) def upload_progress(self, sent, total): self.uploadProgress.emit(self.book_id, sent, total) def log_info(self, msg): self.logger.info('[worker-{}] {}'.format(self.index, msg)) def get_metadata_digest(self): metadata = self.db.get_proxy_metadata(self.book_id) h = sha256() language = next(iter(metadata.languages), None) summary = metadata.comments isbn = metadata.isbn issued_on = metadata.pubdate.date().isoformat() if issued_on == '0101-01-01': issued_on = None h.update(metadata.title.encode('utf-8')) if summary: h.update(summary.encode('utf-8')) if language: h.update(language.encode('utf-8')) if isbn: h.update(isbn.encode('utf-8')) if issued_on: h.update(issued_on.encode('utf-8')) for series_item in self.get_series(metadata): h.update(series_item['title'].encode('utf-8')) if series_item['index'] is not None: h.update(str(series_item['index']).encode('utf-8')) for author in metadata.authors: h.update(author.encode('utf-8')) for tag in metadata.tags: h.update(tag.encode('utf-8')) bookshelves = self.get_bookshelves(metadata) if bookshelves is not None: for bookshelf in bookshelves: h.update(bookshelf.encode('utf-8')) cover_path = self.db.cover(self.book_id, as_path=True) if cover_path: h.update(bytes(path.getsize(cover_path))) h.update(b'\0') with open(cover_path, 'rb') as file: block = file.read(65536) while len(block) > 0: h.update(block) block = file.read(65536) return h.hexdigest() def append_metadata_req_parts(self): metadata = self.db.get_proxy_metadata(self.book_id) language = next(iter(metadata.languages), None) summary = metadata.comments isbn = metadata.isbn issued_on = metadata.pubdate.date().isoformat() if issued_on == '0101-01-01': issued_on = None self.req_body.append( self.build_req_part('metadata[calibre_metadata_digest]', self.metadata_digest)) self.req_body.append( self.build_req_part('metadata[title]', metadata.title)) if summary: self.req_body.append( self.build_req_part('metadata[summary]', summary)) if language: self.req_body.append( self.build_req_part('metadata[language]', language)) if isbn: self.req_body.append(self.build_req_part('metadata[isbn]', isbn)) if issued_on: self.req_body.append( self.build_req_part('metadata[issued_on]', issued_on)) for series_item in self.get_series(metadata): self.req_body.append( self.build_req_part('metadata[series][][title]', series_item['title'])) if series_item['index'] is not None: self.req_body.append( self.build_req_part('metadata[series][][index]', str(series_item['index']))) for author in metadata.authors: self.req_body.append( self.build_req_part('metadata[author_list][]', author)) for tag in metadata.tags: self.req_body.append( self.build_req_part('metadata[tag_list][]', tag)) bookshelves = self.get_bookshelves(metadata) if bookshelves is not None: self.req_body.append( self.build_req_part('metadata[bookshelves][]', '')) for bookshelf in bookshelves: self.req_body.append( self.build_req_part('metadata[bookshelves][]', bookshelf)) cover_path = self.db.cover(self.book_id, as_path=True) if cover_path: self.cover = QFile(cover_path) self.cover.open(QIODevice.ReadOnly) self.req_body.append( self.build_req_part('metadata[cover]', self.cover)) else: self.cover = None def clean_metadata_req(self): if self.cover: self.cover.remove() def build_req_part(self, name, value): part = QHttpPart() part.setHeader(QNetworkRequest.ContentTypeHeader, None) if isinstance(value, QFile): filename = QFileInfo(value).fileName() part.setHeader( QNetworkRequest.ContentDispositionHeader, 'form-data; name="{}"; filename="{}"'.format( self.escape_quotes(name), self.escape_quotes(filename))) part.setBodyDevice(value) else: part.setHeader( QNetworkRequest.ContentDispositionHeader, 'form-data; name="{}"'.format(self.escape_quotes(name))) part.setBody(value.encode('utf-8')) return part def complete_req(self, tag, return_json=False): retry = False abort = False if self.canceled: abort = True error = self.reply.error() resp = None if error == QNetworkReply.AuthenticationRequiredError: abort = True self.aborted.emit('Invalid API key.') self.log_info('{}: AuthenticationRequiredError'.format(tag)) elif error == QNetworkReply.NoError: resp = self.reply.readAll() self.log_info('{} response: {}'.format(tag, resp)) if return_json: try: resp = json.loads(resp.data()) except ValueError as e: resp = None self.log_info('{}: {}'.format(tag, e)) self.failed.emit(self.book_id, 'Cannot parse the server response') elif error == QNetworkReply.UnknownContentError: if self.reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) == 422: err_resp = self.reply.readAll() self.log_info('{} response: {}'.format(tag, err_resp)) msg = json.loads(err_resp.data())['error'] self.failed.emit(self.book_id, msg) else: self.log_info('{}: UnknownContentError'.format(tag)) elif error == QNetworkReply.InternalServerError: self.log_info('{}: InternalServerError'.format(tag)) err_resp = self.reply.readAll() self.log_info('{} response: {}'.format(tag, err_resp)) elif error == QNetworkReply.UnknownServerError: self.log_info('{}: UnknownServerError'.format(tag)) err_resp = self.reply.readAll() self.log_info('{} response: {}'.format(tag, err_resp)) elif error == QNetworkReply.ConnectionRefusedError or \ error == QNetworkReply.RemoteHostClosedError or \ error == QNetworkReply.HostNotFoundError or \ error == QNetworkReply.TimeoutError or \ error == QNetworkReply.TemporaryNetworkFailureError: retry = True self.log_info('{}: {}'.format(tag, error)) elif error == QNetworkReply.OperationCanceledError: abort = True self.log_info('{}: OperationCanceledError'.format(tag)) else: abort = True self.aborted.emit('Error {}.'.format(error)) self.log_info('{} error: {}'.format(tag, error)) self.reply.deleteLater() self.reply = None if retry: self.retries += 1 if self.retries > 2: self.retries = 0 self.aborted.emit('Error {}.'.format(error)) retry = False else: abort = False else: self.retries = 0 return (resp, retry, abort) def calculate_digest(self): if self.digest is not None: return h = sha256() h.update(bytes(path.getsize(self.file_path))) h.update(b'\0') with open(self.file_path, 'rb') as file: block = file.read(65536) while len(block) > 0: h.update(block) block = file.read(65536) self.digest = h.hexdigest() def escape_quotes(self, value): return value.replace('"', '\\"') def set_bookfusion_id(self, bookfusion_id): identifiers = self.db.get_proxy_metadata(self.book_id).identifiers identifiers['bookfusion'] = str(bookfusion_id) self.db.set_field('identifiers', {self.book_id: identifiers}) def get_bookshelves(self, metadata): bookshelves_custom_column = prefs['bookshelves_custom_column'] if bookshelves_custom_column: try: bookshelves = getattr(metadata, bookshelves_custom_column) except AttributeError: return None if bookshelves is None: return [] if isinstance(bookshelves, list): return bookshelves else: return [bookshelves] else: return None def get_series(self, metadata): series_items = [] if metadata.series: series_items.append({ 'title': metadata.series, 'index': metadata.series_index }) for key, meta in self.db.field_metadata.custom_iteritems(): if meta['datatype'] == 'series': title = getattr(metadata, key) if title: found = False for series_item in series_items: if series_item['title'].lower() == title.lower(): found = True if not found: index = getattr(metadata, key + '_index') series_items.append({'title': title, 'index': index}) return series_items