def find_book_in_db(myDB, author, book): # prefer an exact match on author & book match = myDB.action("SELECT BookID FROM books where AuthorName=? and BookName=?", [author, book]).fetchone() if match: logger.debug("Exact match [%s]" % book) return match["BookID"] else: # No exact match # Try a more complex fuzzy match against each book in the db by this author # Using hard-coded ratios for now, ratio high (>90), partial_ratio lower (>65) # These are results that work well on my library, minimal false matches and no misses on books that should be matched # Maybe make ratios configurable in config.ini later # books = myDB.select('SELECT BookID,BookName FROM books where AuthorName="%s"' % author) best_ratio = 0 best_partial = 0 ratio_name = "" partial_name = "" ratio_id = 0 partial_id = 0 logger.debug("Found %s books for %s" % (len(books), author)) for a_book in books: # lowercase everything to raise fuzziness scores book_lower = book.lower() a_book_lower = a_book["BookName"].lower() # ratio = fuzz.ratio(book_lower, a_book_lower) partial = fuzz.partial_ratio(book_lower, a_book_lower) if ratio > best_ratio: best_ratio = ratio ratio_name = a_book["BookName"] ratio_id = a_book["BookID"] if partial > best_partial: best_partial = partial partial_name = a_book["BookName"] partial_id = a_book["BookID"] else: if partial == best_partial: # prefer the match closest to the left, ie prefer starting with a match and ignoring the rest # this eliminates most false matches against omnibuses if a_book_lower.find(book_lower) < partial_name.lower().find(book_lower): logger.debug("Fuzz left prefer [%s] over [%s]" % (a_book["BookName"], partial_name)) best_partial = partial partial_name = a_book["BookName"] partial_id = a_book["BookID"] # if best_ratio > 90: logger.debug("Fuzz match ratio [%d] [%s] [%s]" % (best_ratio, book, ratio_name)) return ratio_id if best_partial > 65: logger.debug("Fuzz match partial [%d] [%s] [%s]" % (best_partial, book, partial_name)) return partial_id logger.debug( "Fuzz failed [%s - %s] ratio [%d,%s], partial [%d,%s]" % (author, book, best_ratio, ratio_name, best_partial, partial_name) ) return 0
def find_book_in_db(myDB, author, book): # PAB fuzzy search for book in library, return LL bookid if found or zero # if not, return bookid to more easily update status # prefer an exact match on author & book match = myDB.action( 'SELECT BookID FROM books where AuthorName="%s" and BookName="%s"' % (author, book)).fetchone() if match: logger.debug('Exact match [%s]' % book) return match['BookID'] else: # No exact match # Try a more complex fuzzy match against each book in the db by this author # Using hard-coded ratios for now, ratio high (>90), partial_ratio lower (>65) # These are results that work well on my library, minimal false matches and no misses # on books that should be matched # Maybe make ratios configurable in config.ini later books = myDB.select('SELECT BookID,BookName FROM books where AuthorName="%s"' % author) best_ratio = 0 best_partial = 0 ratio_name = "" partial_name = "" ratio_id = 0 partial_id = 0 #logger.debug("Found %s books for %s" % (len(books), author)) for a_book in books: # tidy up everything to raise fuzziness scores # still need to lowercase for matching against partial_name later on book_lower = common.remove_accents(book.lower()) a_book_lower = common.remove_accents(a_book['BookName'].lower()) # ratio = fuzz.ratio(book_lower, a_book_lower) partial = fuzz.partial_ratio(book_lower, a_book_lower) if ratio > best_ratio: best_ratio = ratio ratio_name = a_book['BookName'] ratio_id = a_book['BookID'] if partial > best_partial: best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] else: if partial == best_partial: # prefer the match closest to the left, ie prefer starting with a match and ignoring the rest # this eliminates most false matches against omnibuses if a_book_lower.find(book_lower) < partial_name.lower().find(book_lower): logger.debug( "Fuzz left prefer [%s] over [%s]" % (a_book['BookName'], partial_name)) best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] # if best_ratio > 90: logger.debug( "Fuzz match ratio [%d] [%s] [%s]" % (best_ratio, book, ratio_name)) return ratio_id if best_partial > 65: logger.debug( "Fuzz match partial [%d] [%s] [%s]" % (best_partial, book, partial_name)) return partial_id logger.debug( 'Fuzz failed [%s - %s] ratio [%d,%s], partial [%d,%s]' % (author, book, best_ratio, ratio_name, best_partial, partial_name)) return 0
def searchbook(books=None): # rename this thread threading.currentThread().name = "SEARCHBOOKS" myDB = database.DBConnection() searchlist = [] searchlist1 = [] if books is None: # We are performing a backlog search searchbooks = myDB.select('SELECT BookID, AuthorName, Bookname from books WHERE Status="Wanted"') # Clear cache if os.path.exists(".ProviderCache"): for f in os.listdir(".ProviderCache"): os.unlink("%s/%s" % (".ProviderCache", f)) # Clearing throttling timeouts t = SimpleCache.ThrottlingProcessor() t.lastRequestTime.clear() else: # The user has added a new book searchbooks = [] for book in books: searchbook = myDB.select('SELECT BookID, AuthorName, BookName from books WHERE BookID=? AND Status="Wanted"', [book['bookid']]) for terms in searchbook: searchbooks.append(terms) for searchbook in searchbooks: bookid = searchbook[0] author = searchbook[1] book = searchbook[2] dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':'', ':':'', ';':''} dicSearchFormatting = {'.':' +', ' + ':' '} author = formatter.latinToAscii(formatter.replace_all(author, dic)) book = formatter.latinToAscii(formatter.replace_all(book, dic)) # TRY SEARCH TERM just using author name and book type author = formatter.latinToAscii(formatter.replace_all(author, dicSearchFormatting)) searchterm1 = author # + ' ' + lazylibrarian.EBOOK_TYPE searchterm1 = re.sub('[\.\-\/]', ' ', searchterm1).encode('utf-8') searchterm1 = re.sub(r'\(.*?\)', '', searchterm1).encode('utf-8') searchterm1 = re.sub(r"\s\s+" , " ", searchterm1) # strip any double white space searchlist.append({"bookid": bookid, "bookName":searchbook[2], "authorName":searchbook[1], "searchterm": searchterm1.strip()}) if not lazylibrarian.SAB_HOST and not lazylibrarian.BLACKHOLE: logger.info('No download method is set, use SABnzbd or blackhole') if not lazylibrarian.NEWZNAB and not lazylibrarian.NEWZNAB2: logger.info('No providers are set. use NEWZNAB.') counter = 0 for book in searchlist: resultlist = [] if lazylibrarian.NEWZNAB: logger.debug('Searching NZB\'s at provider %s ...' % lazylibrarian.NEWZNAB_HOST) resultlist = providers.NewzNab(book, "1") if lazylibrarian.NEWZNAB2: logger.debug('Searching NZB\'s at provider %s ...' % lazylibrarian.NEWZNAB_HOST2) resultlist += providers.NewzNab(book, "2") if not resultlist: logger.debug("Adding book %s to queue." % book['searchterm']) else: dictrepl = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':'', '(':'', ')':'', '[':'', ']':'', '#':'', '0':'', '1':'', '2':'', '3':'', '4':'', '5':'', '6':'', '7':'', '8':'' , '9':'', '\'':'', ':':'', '!':'', '-':'', '\s\s':' ', ' the ':' ', ' a ':' ', ' and ':' ', ' to ':' ', ' of ':' ', ' for ':' ', ' my ':' ', ' in ':' ', ' at ':' ', ' with ':' ' } bookName = book['bookName'] bookID = book['bookid'] bookName = re.sub('[\.\-\/]', ' ', bookName) bookName = re.sub(r'\(.*?\)', '', bookName) bookName = formatter.latinToAscii(formatter.replace_all(bookName.lower(), dictrepl)).strip() logger.debug(u'bookName %s' % bookName) addedCounter = 0 for nzb in resultlist: nzbTitle = formatter.latinToAscii(formatter.replace_all(str(nzb['nzbtitle']).lower(), dictrepl)).strip() logger.debug(u'nzbName %s' % nzbTitle) logger.debug("NZB Match %: " + str(fuzz.partial_ratio(bookName, nzbTitle))) if (fuzz.partial_ratio(bookName, nzbTitle) > 80): logger.debug(u'FOUND %s' % nzbTitle.lower()) addedCounter = addedCounter + 1 bookid = nzb['bookid'] nzbTitle = (book["authorName"] + ' - ' + book['bookName'] + ' LL.(' + bookID + ')').strip() nzburl = nzb['nzburl'] nzbprov = nzb['nzbprov'] controlValueDict = {"NZBurl": nzburl} newValueDict = { "NZBprov": nzbprov, "BookID": bookid, "NZBdate": formatter.today(), "NZBtitle": nzbTitle, "Status": "Skipped" } myDB.upsert("wanted", newValueDict, controlValueDict) snatchedbooks = myDB.action('SELECT * from books WHERE BookID=? and Status="Snatched"', [bookid]).fetchone() if not snatchedbooks: snatch = DownloadMethod(bookid, nzbprov, nzbTitle, nzburl) break; if addedCounter == 0: logger.info("No nzb's found for " + (book["authorName"] + ' ' + bookName).strip() + ". Adding book to queue.") counter = counter + 1
def find_book_in_db(myDB, author, book): # PAB fuzzy search for book in library, return LL bookid if found or zero # if not, return bookid to more easily update status # prefer an exact match on author & book match = myDB.match('SELECT BookID FROM books where AuthorName="%s" and BookName="%s"' % (author.replace('"', '""'), book.replace('"', '""'))) if match: logger.debug('Exact match [%s]' % book) return match['BookID'] else: # Try a more complex fuzzy match against each book in the db by this author # Using hard-coded ratios for now, ratio high (>90), partial_ratio lower (>85) # These are results that work well on my library, minimal false matches and no misses # on books that should be matched # Maybe make ratios configurable in config.ini later books = myDB.select('SELECT BookID,BookName,BookISBN FROM books where AuthorName="%s"' % author.replace('"', '""')) best_ratio = 0 best_partial = 0 best_partname = 0 ratio_name = "" partial_name = "" partname_name = "" ratio_id = 0 partial_id = 0 partname_id = 0 partname = 0 book_lower = unaccented(book.lower()) book_partname, book_sub = split_title(author, book_lower) if book_partname == book_lower: book_partname = '' for a_book in books: # tidy up everything to raise fuzziness scores # still need to lowercase for matching against partial_name later on a_book_lower = unaccented(a_book['BookName'].lower()) # ratio = fuzz.ratio(book_lower, a_book_lower) partial = fuzz.partial_ratio(book_lower, a_book_lower) if book_partname: partname = fuzz.partial_ratio(book_partname, a_book_lower) # lose a point for each extra word in the fuzzy matches so we get the closest match words = len(getList(book_lower)) words -= len(getList(a_book_lower)) ratio -= abs(words) partial -= abs(words) if ratio > best_ratio: best_ratio = ratio ratio_name = a_book['BookName'] ratio_id = a_book['BookID'] if partial > best_partial: best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] if partname > best_partname: best_partname = partname partname_name = a_book['BookName'] partname_id = a_book['BookID'] if partial == best_partial: # prefer the match closest to the left, ie prefer starting with a match and ignoring the rest # this eliminates most false matches against omnibuses when we want a single book # find the position of the shortest string in the longest if len(getList(book_lower)) >= len(getList(a_book_lower)): match1 = book_lower.find(a_book_lower) else: match1 = a_book_lower.find(book_lower) if len(getList(book_lower)) >= len(getList(partial_name.lower())): match2 = book_lower.find(partial_name.lower()) else: match2 = partial_name.lower().find(book_lower) if match1 < match2: logger.debug( "Fuzz left change, prefer [%s] over [%s] for [%s]" % (a_book['BookName'], partial_name, book)) best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] if best_ratio > 90: logger.debug( "Fuzz match ratio [%d] [%s] [%s]" % (best_ratio, book, ratio_name)) return ratio_id if best_partial > 85: logger.debug( "Fuzz match partial [%d] [%s] [%s]" % (best_partial, book, partial_name)) return partial_id if best_partname > 95: logger.debug( "Fuzz match partname [%d] [%s] [%s]" % (best_partname, book, partname_name)) return partname_id logger.debug( 'Fuzz failed [%s - %s] ratio [%d,%s], partial [%d,%s], partname [%d,%s]' % (author, book, best_ratio, ratio_name, best_partial, partial_name, best_partname, partname_name)) return 0
def find_book_in_db(myDB, author, book): # PAB fuzzy search for book in library, return LL bookid if found or zero # if not, return bookid to more easily update status # prefer an exact match on author & book match = myDB.match( 'SELECT BookID FROM books where AuthorName="%s" and BookName="%s"' % (author.replace('"', '""'), book.replace('"', '""'))) if match: logger.debug('Exact match [%s]' % book) return match['BookID'] else: # No exact match # Try a more complex fuzzy match against each book in the db by this author # Using hard-coded ratios for now, ratio high (>90), partial_ratio lower (>75) # These are results that work well on my library, minimal false matches and no misses # on books that should be matched # Maybe make ratios configurable in config.ini later books = myDB.select( 'SELECT BookID,BookName FROM books where AuthorName="%s"' % author.replace('"', '""')) best_ratio = 0 best_partial = 0 best_partname = 0 ratio_name = "" partial_name = "" partname_name = "" ratio_id = 0 partial_id = 0 partname_id = 0 partname = 0 book_lower = unaccented(book.lower()) book_partname = '' if ':' in book_lower: book_partname = book_lower.split(':')[0] for a_book in books: # tidy up everything to raise fuzziness scores # still need to lowercase for matching against partial_name later on a_book_lower = unaccented(a_book['BookName'].lower()) # ratio = fuzz.ratio(book_lower, a_book_lower) partial = fuzz.partial_ratio(book_lower, a_book_lower) if book_partname: partname = fuzz.partial_ratio(book_partname, a_book_lower) # lose a point for each extra word in the fuzzy matches so we get the closest match words = len(getList(book_lower)) words -= len(getList(a_book_lower)) ratio -= abs(words) partial -= abs(words) if ratio > best_ratio: best_ratio = ratio ratio_name = a_book['BookName'] ratio_id = a_book['BookID'] if partial > best_partial: best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] if partname > best_partname: best_partname = partname partname_name = a_book['BookName'] partname_id = a_book['BookID'] if partial == best_partial: # prefer the match closest to the left, ie prefer starting with a match and ignoring the rest # this eliminates most false matches against omnibuses # find the position of the shortest string in the longest if len(getList(book_lower)) >= len(getList(a_book_lower)): match1 = book_lower.find(a_book_lower) else: match1 = a_book_lower.find(book_lower) if len(getList(book_lower)) >= len( getList(partial_name.lower())): match2 = book_lower.find(partial_name.lower()) else: match2 = partial_name.lower().find(book_lower) if match1 < match2: logger.debug( "Fuzz left change, prefer [%s] over [%s] for [%s]" % (a_book['BookName'], partial_name, book)) best_partial = partial partial_name = a_book['BookName'] partial_id = a_book['BookID'] if best_ratio > 90: logger.debug("Fuzz match ratio [%d] [%s] [%s]" % (best_ratio, book, ratio_name)) return ratio_id if best_partial > 75: logger.debug("Fuzz match partial [%d] [%s] [%s]" % (best_partial, book, partial_name)) return partial_id if best_partname > 95: logger.debug("Fuzz match partname [%d] [%s] [%s]" % (best_partname, book, partname_name)) return partname_id logger.debug( 'Fuzz failed [%s - %s] ratio [%d,%s], partial [%d,%s], partname [%d,%s]' % (author, book, best_ratio, ratio_name, best_partial, partial_name, best_partname, partname_name)) return 0
def searchbook(books=None): # rename this thread threading.currentThread().name = "SEARCHBOOKS" myDB = database.DBConnection() searchlist = [] searchlist1 = [] if books is None: # We are performing a backlog search searchbooks = myDB.select( 'SELECT BookID, AuthorName, Bookname from books WHERE Status="Wanted"' ) # Clear cache if os.path.exists(".ProviderCache"): for f in os.listdir(".ProviderCache"): os.unlink("%s/%s" % (".ProviderCache", f)) # Clearing throttling timeouts t = SimpleCache.ThrottlingProcessor() t.lastRequestTime.clear() else: # The user has added a new book searchbooks = [] for book in books: searchbook = myDB.select( 'SELECT BookID, AuthorName, BookName from books WHERE BookID=? AND Status="Wanted"', [book['bookid']]) for terms in searchbook: searchbooks.append(terms) for searchbook in searchbooks: bookid = searchbook[0] author = searchbook[1] book = searchbook[2] dic = { '...': '', ' & ': ' ', ' = ': ' ', '?': '', '$': 's', ' + ': ' ', '"': '', ',': '', '*': '', ':': '', ';': '' } dicSearchFormatting = {'.': ' +', ' + ': ' '} author = formatter.latinToAscii(formatter.replace_all(author, dic)) book = formatter.latinToAscii(formatter.replace_all(book, dic)) # TRY SEARCH TERM just using author name and book type author = formatter.latinToAscii( formatter.replace_all(author, dicSearchFormatting)) searchterm1 = author # + ' ' + lazylibrarian.EBOOK_TYPE searchterm1 = re.sub('[\.\-\/]', ' ', searchterm1).encode('utf-8') searchterm1 = re.sub(r'\(.*?\)', '', searchterm1).encode('utf-8') searchterm1 = re.sub(r"\s\s+", " ", searchterm1) # strip any double white space searchlist.append({ "bookid": bookid, "bookName": searchbook[2], "authorName": searchbook[1], "searchterm": searchterm1.strip() }) if not lazylibrarian.SAB_HOST and not lazylibrarian.BLACKHOLE: logger.info('No download method is set, use SABnzbd or blackhole') if not lazylibrarian.NEWZNAB and not lazylibrarian.NEWZNAB2: logger.info('No providers are set. use NEWZNAB.') counter = 0 for book in searchlist: resultlist = [] if lazylibrarian.NEWZNAB: logger.debug('Searching NZB\'s at provider %s ...' % lazylibrarian.NEWZNAB_HOST) resultlist = providers.NewzNab(book, "1") if lazylibrarian.NEWZNAB2: logger.debug('Searching NZB\'s at provider %s ...' % lazylibrarian.NEWZNAB_HOST2) resultlist += providers.NewzNab(book, "2") if not resultlist: logger.debug("Adding book %s to queue." % book['searchterm']) else: dictrepl = { '...': '', ' & ': ' ', ' = ': ' ', '?': '', '$': 's', ' + ': ' ', '"': '', ',': '', '*': '', '(': '', ')': '', '[': '', ']': '', '#': '', '0': '', '1': '', '2': '', '3': '', '4': '', '5': '', '6': '', '7': '', '8': '', '9': '', '\'': '', ':': '', '!': '', '-': '', '\s\s': ' ', ' the ': ' ', ' a ': ' ', ' and ': ' ', ' to ': ' ', ' of ': ' ', ' for ': ' ', ' my ': ' ', ' in ': ' ', ' at ': ' ', ' with ': ' ' } bookName = book['bookName'] bookID = book['bookid'] bookName = re.sub('[\.\-\/]', ' ', bookName) bookName = re.sub(r'\(.*?\)', '', bookName) bookName = formatter.latinToAscii( formatter.replace_all(bookName.lower(), dictrepl)).strip() logger.debug(u'bookName %s' % bookName) addedCounter = 0 for nzb in resultlist: nzbTitle = formatter.latinToAscii( formatter.replace_all( str(nzb['nzbtitle']).lower(), dictrepl)).strip() logger.debug(u'nzbName %s' % nzbTitle) logger.debug("NZB Match %: " + str(fuzz.partial_ratio(bookName, nzbTitle))) if (fuzz.partial_ratio(bookName, nzbTitle) > 80): logger.debug(u'FOUND %s' % nzbTitle.lower()) addedCounter = addedCounter + 1 bookid = nzb['bookid'] nzbTitle = (book["authorName"] + ' - ' + book['bookName'] + ' LL.(' + bookID + ')').strip() nzburl = nzb['nzburl'] nzbprov = nzb['nzbprov'] controlValueDict = {"NZBurl": nzburl} newValueDict = { "NZBprov": nzbprov, "BookID": bookid, "NZBdate": formatter.today(), "NZBtitle": nzbTitle, "Status": "Skipped" } myDB.upsert("wanted", newValueDict, controlValueDict) snatchedbooks = myDB.action( 'SELECT * from books WHERE BookID=? and Status="Snatched"', [bookid]).fetchone() if not snatchedbooks: snatch = DownloadMethod(bookid, nzbprov, nzbTitle, nzburl) break if addedCounter == 0: logger.info("No nzb's found for " + (book["authorName"] + ' ' + bookName).strip() + ". Adding book to queue.") counter = counter + 1
def searchbook(books=None): # rename this thread threading.currentThread().name = "SEARCHBOOKS" logger.debug("Book search has begun.") myDB = database.DBConnection() searchlist = [] searchlist1 = [] if books is None: # We are performing a backlog search searchbooks = myDB.select('SELECT BookID, AuthorName, Bookname from books WHERE Status="Wanted"') # Clear cache if os.path.exists(".ProviderCache"): for f in os.listdir(".ProviderCache"): os.unlink("%s/%s" % (".ProviderCache", f)) # Clearing throttling timeouts t = SimpleCache.ThrottlingProcessor() t.lastRequestTime.clear() else: # The user has added a new book searchbooks = [] for book in books: searchbook = myDB.select( 'SELECT BookID, AuthorName, BookName from books WHERE BookID=? AND Status="Wanted"', [book["bookid"]] ) for terms in searchbook: searchbooks.append(terms) for searchbook in searchbooks: bookid = searchbook[0] author = searchbook[1] book = searchbook[2] dic = { "...": "", " & ": " ", " = ": " ", "?": "", "$": "s", " + ": " ", '"': "", ",": "", "*": "", ":": "", ";": "", } dicSearchFormatting = {".": " +", " + ": " "} author = formatter.latinToAscii(formatter.replace_all(author, dic)) book = formatter.latinToAscii(formatter.replace_all(book, dic)) # TRY SEARCH TERM just using author name and book type author = formatter.latinToAscii(formatter.replace_all(author, dicSearchFormatting)) searchterm1 = author # + ' ' + lazylibrarian.EBOOK_TYPE searchterm1 = re.sub("[\.\-\/]", " ", searchterm1).encode("utf-8") searchterm1 = re.sub(r"\(.*?\)", "", searchterm1).encode("utf-8") searchterm1 = re.sub(r"\s\s+", " ", searchterm1) # strip any double white space searchlist.append( { "bookid": bookid, "bookName": searchbook[2], "authorName": searchbook[1], "searchterm": searchterm1.strip(), } ) if not lazylibrarian.SAB_HOST and not lazylibrarian.BLACKHOLE: logger.info("No download method is set, use SABnzbd or blackhole") if not lazylibrarian.NEWZNAB and not lazylibrarian.NEWZNAB2: logger.info("No providers are set. use NEWZNAB.") counter = 0 for book in searchlist: resultlist = [] if lazylibrarian.NEWZNAB: logger.debug("Searching NZB's at provider %s ..." % lazylibrarian.NEWZNAB_HOST) resultlist = providers.NewzNab(book, "1") if lazylibrarian.NEWZNAB2: logger.debug("Searching NZB's at provider %s ..." % lazylibrarian.NEWZNAB_HOST2) resultlist += providers.NewzNab(book, "2") if not resultlist: logger.debug("Adding book %s to queue." % book["searchterm"]) else: dictrepl = { "...": "", " & ": " ", " = ": " ", "?": "", "$": "s", " + ": " ", '"': "", ",": "", "*": "", "(": "", ")": "", "[": "", "]": "", "#": "", "0": "", "1": "", "2": "", "3": "", "4": "", "5": "", "6": "", "7": "", "8": "", "9": "", "'": "", ":": "", "!": "", "-": "", "\s\s": " ", " the ": " ", " a ": " ", " and ": " ", " to ": " ", " of ": " ", " for ": " ", " my ": " ", " in ": " ", " at ": " ", " with ": " ", } bookName = book["bookName"] bookID = book["bookid"] bookName = re.sub("[\.\-\/]", " ", bookName) bookName = re.sub(r"\(.*?\)", "", bookName) bookName = formatter.latinToAscii(formatter.replace_all(bookName.lower(), dictrepl)).strip() logger.debug(u"bookName %s" % bookName) addedCounter = 0 for nzb in resultlist: nzbTitle = formatter.latinToAscii(formatter.replace_all(str(nzb["nzbtitle"]).lower(), dictrepl)).strip() logger.debug(u"nzbName %s" % nzbTitle) logger.debug("NZB Match %: " + str(fuzz.partial_ratio(bookName, nzbTitle))) if fuzz.partial_ratio(bookName, nzbTitle) > 80: logger.debug(u"FOUND %s" % nzbTitle.lower()) addedCounter = addedCounter + 1 bookid = nzb["bookid"] nzbTitle = (book["authorName"] + " - " + book["bookName"] + " LL.(" + bookID + ")").strip() nzburl = nzb["nzburl"] nzbprov = nzb["nzbprov"] controlValueDict = {"NZBurl": nzburl} newValueDict = { "NZBprov": nzbprov, "BookID": bookid, "NZBdate": formatter.today(), "NZBtitle": nzbTitle, "Status": "Skipped", } myDB.upsert("wanted", newValueDict, controlValueDict) snatchedbooks = myDB.action( 'SELECT * from books WHERE BookID=? and Status="Snatched"', [bookid] ).fetchone() if not snatchedbooks: snatch = DownloadMethod(bookid, nzbprov, nzbTitle, nzburl) break if addedCounter == 0: logger.info( "No nzb's found for " + (book["authorName"] + " " + bookName).strip() + ". Adding book to queue." ) counter = counter + 1