def getAuthorImage(authorid=None): # tbm=isch search images # tbs=ift:jpg jpeg file type if not authorid: logger.error("getAuthorImage: No authorid") return None cachedir = lazylibrarian.CACHEDIR coverfile = os.path.join(cachedir, "author", authorid + '.jpg') if os.path.isfile(coverfile): # use cached image if there is one lazylibrarian.CACHE_HIT = int(lazylibrarian.CACHE_HIT) + 1 logger.debug(u"getAuthorImage: Returning Cached response for %s" % coverfile) coverlink = 'cache/author/' + authorid + '.jpg' return coverlink lazylibrarian.CACHE_MISS = int(lazylibrarian.CACHE_MISS) + 1 myDB = database.DBConnection() authors = myDB.select( 'select AuthorName from authors where AuthorID="%s"' % authorid) if authors: authorname = safe_unicode(authors[0][0]).encode( lazylibrarian.SYS_ENCODING) safeparams = urllib.quote_plus("author %s" % authorname) URL = "https://www.google.com/search?tbm=isch&tbs=ift:jpg&as_q=" + safeparams result, success = fetchURL(URL) if success: try: img = result.split('url?q=')[1].split('">')[1].split( 'src="')[1].split('"')[0] except IndexError: img = None if img and img.startswith('http'): coverlink, success = cache_img("author", authorid, img) if success: logger.debug("Cached google image for %s" % authorname) return coverlink else: logger.debug("Error getting google image %s, [%s]" % (img, coverlink)) else: logger.debug("No image found in google page for %s" % authorname) else: logger.debug("Error getting google page for %s, [%s]" % (safeparams, result)) else: logger.debug("No author found for %s" % authorid) return None
def pauseAuthor(self, AuthorID): myDB = database.DBConnection() authorsearch = myDB.select( 'SELECT AuthorName from authors WHERE AuthorID=?', [AuthorID]) AuthorName = authorsearch[0]['AuthorName'] logger.info("Pausing author: %s" % AuthorName) controlValueDict = {'AuthorID': AuthorID} newValueDict = {'Status': 'Paused'} myDB.upsert("authors", newValueDict, controlValueDict) logger.debug( 'AuthorID [%s]-[%s] Paused - redirecting to Author home page' % (AuthorID, AuthorName)) raise cherrypy.HTTPRedirect("authorPage?AuthorName=%s" % AuthorName)
def authorPage(self, AuthorName): myDB = database.DBConnection() queryauthors = "SELECT * from authors WHERE AuthorName='%s'" % AuthorName querybooks = "SELECT * from books WHERE AuthorName='%s' order by BookName ASC" % AuthorName author = myDB.action(queryauthors).fetchone() books = myDB.select(querybooks) if author is None: raise cherrypy.HTTPRedirect("home") return serve_template(templatename="author.html", title=author['AuthorName'], author=author, books=books)
def deleteEmptySeries(): """ remove any series from series table that have no entries in member table, return how many deleted """ myDB = database.DBConnection() series = myDB.select('SELECT SeriesID,SeriesName from series') count = 0 for item in series: match = myDB.match('SELECT BookID from member where SeriesID="%s"' % item['SeriesID']) if not match: logger.debug('Deleting empty series %s' % item['SeriesName']) count += 1 myDB.action('DELETE from series where SeriesID="%s"' % item['SeriesID']) return count
def _Serve(self, **kwargs): if 'bookid' in kwargs: if 'fmt' in kwargs: fmt = kwargs['fmt'] else: fmt = '' myid = kwargs['bookid'] myDB = database.DBConnection() res = myDB.match( 'SELECT BookFile,BookName from books where bookid=?', (myid, )) bookfile = res['BookFile'] if fmt: bookfile = os.path.splitext(bookfile)[0] + '.' + fmt self.file = bookfile self.filename = os.path.split(bookfile)[1] return elif 'issueid' in kwargs: myid = kwargs['issueid'] myDB = database.DBConnection() res = myDB.match('SELECT IssueFile from issues where issueid=?', (myid, )) self.file = res['IssueFile'] self.filename = os.path.split(res['IssueFile'])[1] return elif 'audioid' in kwargs: myid = kwargs['audioid'] myDB = database.DBConnection() res = myDB.match( 'SELECT AudioFile,BookName from books where BookID=?', (myid, )) basefile = res['AudioFile'] # zip up all the audiobook parts if basefile and os.path.isfile(basefile): target = zipAudio(os.path.dirname(basefile), res['BookName']) self.file = target self.filename = res['BookName'] + '.zip' return
def export_CSV(search_dir=None, status="Wanted"): """ Write a csv file to the search_dir containing all books marked as "Wanted" """ try: if not search_dir: msg = "Alternate Directory not configured" logger.warn(msg) return msg elif not os.path.isdir(search_dir): msg = "Alternate Directory [%s] not found" % search_dir logger.warn(msg) return msg elif not os.access(search_dir, os.W_OK | os.X_OK): msg = "Alternate Directory [%s] not writable" % search_dir logger.warn(msg) return msg csvFile = os.path.join(search_dir, "%s - %s.csv" % (status, now().replace(':', '-'))) myDB = database.DBConnection() cmd = 'SELECT BookID,AuthorName,BookName,BookIsbn,books.AuthorID FROM books,authors ' cmd += 'WHERE books.Status=? and books.AuthorID = authors.AuthorID' find_status = myDB.select(cmd, (status,)) if not find_status: msg = "No books marked as %s" % status logger.warn(msg) else: count = 0 with open(csvFile, 'wb') as csvfile: csvwrite = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # write headers, change AuthorName BookName BookIsbn to match import csv names (Author, Title, ISBN10) csvwrite.writerow(['BookID', 'Author', 'Title', 'ISBN', 'AuthorID']) for resulted in find_status: logger.debug(u"Exported CSV for book %s" % resulted['BookName']) row = ([resulted['BookID'], resulted['AuthorName'], resulted['BookName'], resulted['BookIsbn'], resulted['AuthorID']]) csvwrite.writerow([("%s" % s).encode(lazylibrarian.SYS_ENCODING) for s in row]) count += 1 msg = "CSV exported %s book%s to %s" % (count, plural(count), csvFile) logger.info(msg) return msg except Exception: msg = 'Unhandled exception in exportCSV: %s' % traceback.format_exc() logger.error(msg) return msg
def addBook(self, bookid=None): myDB = database.DBConnection() booksearch = myDB.select("SELECT * from books WHERE BookID=?", [bookid]) if booksearch: myDB.upsert("books", {'Status': 'Wanted'}, {'BookID': bookid}) for book in booksearch: AuthorName = book['AuthorName'] authorsearch = myDB.select("SELECT * from authors WHERE AuthorName=?", [AuthorName]) if authorsearch: #update authors needs to be updated every time a book is marked differently lastbook = myDB.action("SELECT BookName, BookLink, BookDate from books WHERE AuthorName='%s' AND Status != 'Ignored' order by BookDate DESC" % AuthorName).fetchone() unignoredbooks = myDB.select("SELECT COUNT(BookName) as unignored FROM books WHERE AuthorName='%s' AND Status != 'Ignored'" % AuthorName) bookCount = myDB.select("SELECT COUNT(BookName) as counter FROM books WHERE AuthorName='%s'" % AuthorName) countbooks = myDB.action('SELECT COUNT(*) FROM books WHERE AuthorName="%s" AND (Status="Have" OR Status="Open")' % AuthorName).fetchone() havebooks = int(countbooks[0]) controlValueDict = {"AuthorName": AuthorName} newValueDict = { "TotalBooks": bookCount[0]['counter'], "UnignoredBooks": unignoredbooks[0]['unignored'], "HaveBooks": havebooks, "LastBook": lastbook['BookName'], "LastLink": lastbook['BookLink'], "LastDate": lastbook['BookDate'] } myDB.upsert("authors", newValueDict, controlValueDict) else: if lazylibrarian.BOOK_API == "GoogleBooks": GB = GoogleBooks(bookid) queue = Queue.Queue() find_book = threading.Thread(target=GB.find_book, args=[bookid, queue]) find_book.start() elif lazylibrarian.BOOK_API == "GoodReads": queue = Queue.Queue() GR = GoodReads(bookid) find_book = threading.Thread(target=GR.find_book, args=[bookid, queue]) find_book.start() if len(bookid) == 0: raise cherrypy.HTTPRedirect("config") find_book.join() books = [] mags = False books.append({"bookid": bookid}) threading.Thread(target=searchbook, args=[books, mags]).start() raise cherrypy.HTTPRedirect("books")
def _notify(message, event, force=False): # suppress notifications if the notifier is disabled but the notify options are checked if not lazylibrarian.CONFIG['USE_CUSTOM'] and not force: return False subject = event logger.debug('Custom Event: %s' % event) logger.debug('Custom Message: %s' % message) myDB = database.DBConnection() if subject == "Test": # grab the first entry in the book table data = myDB.match('SELECT * from books') else: # message is a bookid or a magazineid data = myDB.match('SELECT * from books where BookID=?', (message, )) if not data: data = myDB.match('SELECT * from magazines where BookID=?', (message, )) dictionary = dict(zip(data.keys(), data)) dictionary['Event'] = event try: # call the custom notifier script here, passing dictionary deconstructed as strings if lazylibrarian.CONFIG['CUSTOM_SCRIPT']: params = [lazylibrarian.CONFIG['CUSTOM_SCRIPT']] for item in dictionary: params.append(item) if hasattr(dictionary[item], 'encode'): params.append(dictionary[item].encode('utf-8')) else: params.append(str(dictionary[item])) try: res = subprocess.check_output( params, stderr=subprocess.STDOUT).strip() return res except Exception as e: logger.warn('Error sending command: %s' % e) return False else: logger.warn('Error sending custom notification: Check config') return False except Exception as e: logger.warn('Error sending custom notification: %s' % e) return False
def DownloadMethod(bookid=None, nzbprov=None, nzbtitle=None, nzburl=None): myDB = database.DBConnection() if lazylibrarian.SAB_HOST and not lazylibrarian.NZB_DOWNLOADER_BLACKHOLE: download = sabnzbd.SABnzbd(nzbtitle, nzburl) elif lazylibrarian.NZBGET_HOST and not lazylibrarian.NZB_DOWNLOADER_BLACKHOLE: headers = {'User-Agent': USER_AGENT} data = request.request_content(url=nzburl, headers=headers) nzb = classes.NZBDataSearchResult() nzb.extraInfo.append(data) nzb.name = nzbtitle nzb.url = nzburl download = nzbget.sendNZB(nzb) elif lazylibrarian.NZB_DOWNLOADER_BLACKHOLE: try: req = urllib2.Request(nzburl) if lazylibrarian.PROXY_HOST: req.set_proxy(lazylibrarian.PROXY_HOST, lazylibrarian.PROXY_TYPE) req.add_header('User-Agent', USER_AGENT) nzbfile = urllib2.urlopen(req, timeout=90).read() except urllib2.URLError, e: logger.warn('Error fetching nzb from url: ' + nzburl + ' %s' % e) nzbfile = False if (nzbfile): nzbname = str(nzbtitle) + '.nzb' nzbpath = os.path.join(lazylibrarian.NZB_BLACKHOLEDIR, nzbname) try: f = open(nzbpath, 'w') f.write(nzbfile) f.close() logger.info('NZB file saved to: ' + nzbpath) download = True try: os.chmod(nzbpath, 0777) except Exception, e: logger.info("Could not chmod path: " + str(file2)) except Exception, e: logger.error('%s not writable, NZB not saved. Error: %s' % (nzbpath, e)) download = False
def openBook(self, AuthorName=None, action=None, **args): myDB = database.DBConnection() for bookid in args: # ouch dirty workaround... if not bookid == 'book_table_length': controlValueDict = {'BookID': bookid} newValueDict = {'Status': action} myDB.upsert("books", newValueDict, controlValueDict) logger.debug('Status set to %s for BookID: %s' % (action, bookid)) # find book myDB = database.DBConnection() #data = myDB.select('SELECT * from wanted WHERE BookID=\'' + bookid + '\'') bookdata = myDB.select('SELECT * from books WHERE BookID=\'' + bookid + '\'') dest_dir = lazylibrarian.DESTINATION_DIR + '\\' + bookdata[0][ "AuthorName"] + '\\' + bookdata[0]["BookName"] for file2 in os.listdir(dest_dir): logger.info('file ' + str(file2)) if file2.lower().find("." + lazylibrarian.EBOOK_TYPE) > 0: return serve_file(os.path.join(dest_dir, file2), "application/x-download", "attachment")
def searchForMag(self, bookid=None, action=None, **args): myDB = database.DBConnection() # find book bookdata = myDB.select("SELECT * from magazines WHERE Title='%s'" % bookid) if bookdata: # start searchthreads mags = [] mags.append({"bookid": bookid}) books=False threading.Thread(target=searchbook, args=[books, mags]).start() logger.debug("Searching for magazine with title: " + str(bookid)); raise cherrypy.HTTPRedirect("magazines")
def _removeAuthor(self, **kwargs): if 'id' not in kwargs: self.data = 'Missing parameter: id' return else: self.id = kwargs['id'] myDB = database.DBConnection() authorsearch = myDB.select( 'SELECT AuthorName from authors WHERE AuthorID="%s"' % AuthorID) if len(authorsearch): # to stop error if try to remove an author while they are still loading AuthorName = authorsearch[0]['AuthorName'] logger.info(u"Removing all references to author: %s" % AuthorName) myDB.action('DELETE from authors WHERE AuthorID="%s"' % AuthorID) myDB.action('DELETE from books WHERE AuthorID="%s"' % AuthorID)
def dbUpdate(forcefull=False): myDB = database.DBConnection() activeauthors = myDB.select( 'SELECT AuthorID, AuthorName from authors WHERE Status="Active" \ or Status="Loading" order by DateAdded ASC') logger.info('Starting update for %i active authors' % len(activeauthors)) for author in activeauthors: # authorid = author[0] authorname = author[1] importer.addAuthorToDB(authorname, refresh=True) logger.info('Active author update complete')
def markWanted(self, action=None, **args): myDB = database.DBConnection() #I think I need to consolidate bookid in args to unique values... for nzbtitle in args: if not nzbtitle == 'book_table_length': if action != "Delete": controlValueDict = {"NZBtitle": nzbtitle} newValueDict = { "Status": action, } myDB.upsert("wanted", newValueDict, controlValueDict) logger.info('Status of wanted item %s changed to %s' % (nzbtitle, action)) else: myDB.action('DELETE from wanted WHERE NZBtitle=?', [nzbtitle]) logger.info('Item %s removed from wanted' % nzbtitle) raise cherrypy.HTTPRedirect("wanted")
def showJobs(): result = [ "Cache %i hit%s, %i miss" % (int(lazylibrarian.CACHE_HIT), plural(int( lazylibrarian.CACHE_HIT)), int(lazylibrarian.CACHE_MISS)) ] myDB = database.DBConnection() snatched = myDB.match( "SELECT count('Status') as counter from wanted WHERE Status = 'Snatched'" ) wanted = myDB.match( "SELECT count('Status') as counter FROM books WHERE Status = 'Wanted'") result.append("%i item%s marked as Snatched" % (snatched['counter'], plural(snatched['counter']))) result.append("%i item%s marked as Wanted" % (wanted['counter'], plural(wanted['counter']))) author = myDB.match( 'SELECT AuthorID, AuthorName, DateAdded from authors WHERE Status="Active" \ or Status="Loading" order by DateAdded ASC') dtnow = datetime.datetime.now() diff = datecompare(dtnow.strftime("%Y-%m-%d"), author['DateAdded']) result.append('Oldest author info is %s day%s old' % (diff, plural(diff))) for job in lazylibrarian.SCHED.get_jobs(): job = str(job) if "search_magazines" in job: jobname = "Magazine search" elif "checkForUpdates" in job: jobname = "Check LazyLibrarian version" elif "search_tor_book" in job: jobname = "TOR book search" elif "search_nzb_book" in job: jobname = "NZB book search" elif "search_rss_book" in job: jobname = "RSS book search" elif "processDir" in job: jobname = "Process downloads" elif "authorUpdate" in job: jobname = "Update authors" else: jobname = job.split(' ')[0].split('.')[2] # jobinterval = job.split('[')[1].split(']')[0] jobtime = job.split('at: ')[1].split('.')[0] jobtime = next_run(jobtime) jobinfo = "%s: Next run in %s" % (jobname, jobtime) result.append(jobinfo) return result
def seriesInfo(bookid): """ Return series info for a bookid as a dict of formatted strings The strings are configurable, but by default... Full returns ( Lord of the Rings 2 ) Name returns Lord of the Rings (with added Num part if that's not numeric, eg Lord of the Rings Book One) Num returns Book #1 - (or empty string if no numeric part) so you can combine to make Book #1 - Lord of the Rings """ mydict = {'Name': '', 'Full': '', 'Num': ''} myDB = database.DBConnection() cmd = 'SELECT SeriesID,SeriesNum from member WHERE bookid=?' res = myDB.match(cmd, (bookid,)) if not res: return mydict seriesid = res['SeriesID'] serieslist = getList(res['SeriesNum']) seriesnum = '' seriesname = '' # might be "Book 3.5" or similar, just get the numeric part while serieslist: seriesnum = serieslist.pop() try: _ = float(seriesnum) break except ValueError: seriesnum = '' pass if not seriesnum: # couldn't figure out number, keep everything we got, could be something like "Book Two" serieslist = res['SeriesNum'] cmd = 'SELECT SeriesName from series WHERE seriesid=?' res = myDB.match(cmd, (seriesid,)) if res: seriesname = res['SeriesName'] if not seriesnum: # add what we got back to end of series name if serieslist: seriesname = "%s %s" % (seriesname, serieslist) mydict['Name'] = lazylibrarian.CONFIG['FMT_SERNAME'].replace('$SerName', seriesname).replace('$$', ' ') mydict['Num'] = lazylibrarian.CONFIG['FMT_SERNUM'].replace('$SerNum', seriesnum).replace('$$', ' ') mydict['Full'] = lazylibrarian.CONFIG['FMT_SERIES'].replace('$SerNum', seriesnum).replace( '$SerName', seriesname).replace('$$', ' ') return mydict
def update_totals(AuthorID): myDB = database.DBConnection() # author totals needs to be updated every time a book is marked differently match = myDB.select('SELECT AuthorID from authors WHERE AuthorID=?', (AuthorID, )) if not match: logger.debug('Update_totals - authorid [%s] not found' % AuthorID) return cmd = 'SELECT BookName, BookLink, BookDate, BookID from books WHERE AuthorID=?' cmd += ' AND Status != "Ignored" order by BookDate DESC' lastbook = myDB.match(cmd, (AuthorID, )) cmd = "select sum(case status when 'Ignored' then 0 else 1 end) as unignored," cmd += "sum(case when status == 'Have' then 1 when status == 'Open' then 1 " cmd += "when audiostatus == 'Have' then 1 when audiostatus == 'Open' then 1 " cmd += "else 0 end) as have, count(*) as total from books where authorid=?" totals = myDB.match(cmd, (AuthorID, )) controlValueDict = {"AuthorID": AuthorID} newValueDict = { "TotalBooks": totals['total'], "UnignoredBooks": totals['unignored'], "HaveBooks": totals['have'], "LastBook": lastbook['BookName'] if lastbook else None, "LastLink": lastbook['BookLink'] if lastbook else None, "LastBookID": lastbook['BookID'] if lastbook else None, "LastDate": lastbook['BookDate'] if lastbook else None } myDB.upsert("authors", newValueDict, controlValueDict) cmd = "select series.seriesid as Series,sum(case books.status when 'Ignored' then 0 else 1 end) as Total," cmd += "sum(case when books.status == 'Have' then 1 when books.status == 'Open' then 1" cmd += " when books.audiostatus == 'Have' then 1 when books.audiostatus == 'Open' then 1" cmd += " else 0 end) as Have from books,member,series,seriesauthors where member.bookid=books.bookid" cmd += " and member.seriesid = series.seriesid and seriesauthors.seriesid = series.seriesid" cmd += " and seriesauthors.authorid=? group by series.seriesid" res = myDB.select(cmd, (AuthorID, )) if len(res): for series in res: myDB.action('UPDATE series SET Have=?, Total=? WHERE SeriesID=?', (series['Have'], series['Total'], series['Series'])) res = myDB.match('SELECT AuthorName from authors WHERE AuthorID=?', (AuthorID, )) logger.debug('Updated totals for [%s]' % res['AuthorName'])
def find_book(self, bookid=None, queue=None): threading.currentThread().name = "GR-ADD-BOOK" myDB = database.DBConnection() URL = 'https://www.goodreads.com/book/show/' + bookid + '?' + urllib.urlencode(self.params) try: # Cache our request request = urllib2.Request(URL) if lazylibrarian.PROXY_HOST: request.set_proxy(lazylibrarian.PROXY_HOST, lazylibrarian.PROXY_TYPE) request.add_header('User-Agent', USER_AGENT) opener = urllib2.build_opener(SimpleCache.CacheHandler(".AuthorCache"), SimpleCache.ThrottlingProcessor(5)) resp = opener.open(request) sourcexml = ElementTree.parse(resp) except Exception, e: logger.error("Error fetching book info: " + str(e))
def CheckFolder(): myDB = database.DBConnection() snatched = myDB.select('SELECT * from wanted WHERE Status="Snatched"') pp_path = lazylibrarian.SAB_DIR if snatched: for book in snatched: logger.info(book['BookID']) pp_pathsub = os.path.join(pp_path, book['NZBtitle']) if os.path.exists(pp_pathsub): logger.debug('Found %s. Processing %s' % (book['NZBtitle'], pp_pathsub)) processPath(book['BookID'], pp_pathsub) else: logger.error('No path found for: %s. Can\'t process it.' % book['NZBtitle']) else: logger.info('No books with status Snatched are found, nothing to process.')
def _addMagazine(self, **kwargs): if 'name' not in kwargs: self.data = 'Missing parameter: name' return else: self.id = kwargs['name'] myDB = database.DBConnection() controlValueDict = {"Title": self.id} newValueDict = { "Regex": None, "Status": "Active", "MagazineAdded": today(), "IssueStatus": "Wanted", "Reject": None } myDB.upsert("magazines", newValueDict, controlValueDict)
def setAllBookSeries(): """ Try to set series details for all books from workpages""" myDB = database.DBConnection() books = myDB.select('select BookID from books where Manual is not "1"') counter = 0 if books: logger.info('Checking series for %s book%s' % (len(books), plural(len(books)))) for book in books: bookid = book['BookID'] seriesdict = getWorkSeries(bookid) if seriesdict: counter += 1 setSeries(seriesdict, bookid) deleteEmptySeries() msg = 'Updated %s book%s' % (counter, plural(counter)) logger.info('Series check complete: ' + msg) return msg
def showJobs(): result = ["Cache %i hit%s, %i miss" % (check_int(lazylibrarian.CACHE_HIT, 0), plural(check_int(lazylibrarian.CACHE_HIT, 0)), check_int(lazylibrarian.CACHE_MISS, 0))] myDB = database.DBConnection() snatched = myDB.match("SELECT count('Status') as counter from wanted WHERE Status = 'Snatched'") wanted = myDB.match("SELECT count('Status') as counter FROM books WHERE Status = 'Wanted'") result.append("%i item%s marked as Snatched" % (snatched['counter'], plural(snatched['counter']))) result.append("%i item%s marked as Wanted" % (wanted['counter'], plural(wanted['counter']))) for job in lazylibrarian.SCHED.get_jobs(): job = str(job) if "search_magazines" in job: jobname = "Magazine search" elif "checkForUpdates" in job: jobname = "Check LazyLibrarian version" elif "search_book" in job: jobname = "Book search" elif "search_rss_book" in job: jobname = "RSS book search" elif "processDir" in job: jobname = "Process downloads" elif "authorUpdate" in job: jobname = "Update authors" elif "sync_to_gr" in job: jobname = "Goodreads Sync" else: jobname = job.split(' ')[0].split('.')[2] # jobinterval = job.split('[')[1].split(']')[0] jobtime = job.split('at: ')[1].split('.')[0] jobtime = next_run(jobtime) timeparts = jobtime.split(' ') if timeparts[0] == '1' and timeparts[1].endswith('s'): timeparts[1] = timeparts[1][:-1] jobinfo = "%s: Next run in %s %s" % (jobname, timeparts[0], timeparts[1]) result.append(jobinfo) cmd = 'SELECT AuthorID, AuthorName, DateAdded from authors WHERE Status="Active" or Status="Loading"' cmd += 'or Status="Wanted" order by DateAdded ASC' author = myDB.match(cmd) dtnow = datetime.datetime.now() diff = datecompare(dtnow.strftime("%Y-%m-%d"), author['DateAdded']) result.append('Oldest author info (%s) is %s day%s old' % (author['AuthorName'], diff, plural(diff))) return result
def _setimage(self, table, itemid, img): msg = "%s Image [%s] rejected" % (table, img) # Cache file image if os.path.isfile(img): extn = os.path.splitext(img)[1].lower() if extn and extn in ['.jpg', '.jpeg', '.png']: destfile = os.path.join(lazylibrarian.CACHEDIR, table, itemid + '.jpg') try: shutil.copy(img, destfile) setperm(destfile) msg = '' except Exception as why: msg += " Failed to copy file: %s %s" % (type(why).__name__, str(why)) else: msg += " invalid extension" if img.startswith('http'): # cache image from url extn = os.path.splitext(img)[1].lower() if extn and extn in ['.jpg', '.jpeg', '.png']: cachedimg, success = cache_img(table, itemid, img) if success: msg = '' else: msg += " Failed to cache file" else: msg += " invalid extension" elif msg: msg += " Not found" if msg: self.data = msg return myDB = database.DBConnection() dbentry = myDB.match('SELECT %sID from %ss WHERE %sID=%s' % (table, table, table, itemid)) if dbentry: myDB.action('UPDATE %ss SET %sImg="%s" WHERE %sID=%s' % (table, table, 'cache' + os.sep + itemid + '.jpg', table, itemid)) else: self.data = "%sID %s not found" % (table, itemid)
def isbn_from_words(words): """ Use Google to get an ISBN for a book from words in title and authors name. Store the results in the database """ myDB = database.DBConnection() res = myDB.match("SELECT ISBN from isbn WHERE Words=?", (words,)) if res: logger.debug('Found cached ISBN for %s' % words) return res['ISBN'] baseurl = "http://www.google.com/search?q=ISBN+" if not PY2: search_url = baseurl + quote(words.replace(' ', '+')) else: search_url = baseurl + words.replace(' ', '+') headers = {'User-Agent': 'w3m/0.5.3', 'Content-Type': 'text/plain; charset="UTF-8"', 'Content-Transfer-Encoding': 'Quoted-Printable', } content, success = fetchURL(search_url, headers=headers) # noinspection Annotator RE_ISBN13 = re.compile(r'97[89]{1}(?:-?\d){10,16}|97[89]{1}[- 0-9]{10,16}') RE_ISBN10 = re.compile(r'ISBN\x20(?=.{13}$)\d{1,5}([- ])\d{1,7}\1\d{1,6}\1(\d|X)$|[- 0-9X]{10,16}') # take the first valid looking answer res = RE_ISBN13.findall(content) logger.debug('Found %s ISBN13 for %s' % (len(res), words)) for item in res: if len(item) > 13: item = item.replace('-', '').replace(' ', '') if len(item) == 13: myDB.action("INSERT into isbn (Words, ISBN) VALUES (?, ?)", (words, item)) return item res = RE_ISBN10.findall(content) logger.debug('Found %s ISBN10 for %s' % (len(res), words)) for item in res: if len(item) > 10: item = item.replace('-', '').replace(' ', '') if len(item) == 10: myDB.action("INSERT into isbn (Words, ISBN) VALUES (?, ?)", (words, item)) return item logger.debug('No valid ISBN found for %s' % words) return None
def finditem(item, preferred_authorname): """ Try to find book matching the csv item in the database Return database entry, or False if not found """ myDB = database.DBConnection() bookmatch = "" isbn10 = "" isbn13 = "" bookid = "" bookname = item['Title'] bookname = makeUnicode(bookname) if 'ISBN' in item: isbn10 = item['ISBN'] if 'ISBN13' in item: isbn13 = item['ISBN13'] if 'BookID' in item: bookid = item['BookID'] # try to find book in our database using bookid or isbn, or if that fails, name matching cmd = 'SELECT AuthorName,BookName,BookID,books.Status FROM books,authors where books.AuthorID = authors.AuthorID ' if bookid: fullcmd = cmd + 'and BookID=?' bookmatch = myDB.match(fullcmd, (bookid, )) if not bookmatch: if is_valid_isbn(isbn10): fullcmd = cmd + 'and BookIsbn=?' bookmatch = myDB.match(fullcmd, (isbn10, )) if not bookmatch: if is_valid_isbn(isbn13): fullcmd = cmd + 'and BookIsbn=?' bookmatch = myDB.match(fullcmd, (isbn13, )) if not bookmatch: bookid, mtype = find_book_in_db(preferred_authorname, bookname, ignored=False) if bookid and mtype == "Ignored": logger.warn( "Book %s by %s is marked Ignored in database, importing anyway" % (bookname, preferred_authorname)) if bookid: fullcmd = cmd + 'and BookID=?' bookmatch = myDB.match(fullcmd, (bookid, )) return bookmatch
def DownloadMethod(bookid=None, nzbprov=None, nzbtitle=None, nzburl=None): myDB = database.DBConnection() if lazylibrarian.SAB_HOST and not lazylibrarian.BLACKHOLE: download = sabnzbd.SABnzbd(nzbtitle, nzburl) logger.debug('Nzbfile has been downloaded from ' + str(nzburl)) myDB.action('UPDATE books SET status = "Snatched" WHERE BookID=?', [bookid]) myDB.action('UPDATE wanted SET status = "Snatched" WHERE BookID=?', [bookid]) elif lazylibrarian.BLACKHOLE: try: req = urllib2.Request(nzburl) req.add_header( 'User-Agent', 'lazylibrary/0.0 +https://github.com/herman-rogers/LazyLibrarian-1' ) nzbfile = urllib2.urlopen(req, timeout=90).read() except urllib2.URLError, e: logger.warn('Error fetching nzb from url: ' + nzburl + ' %s' % e) nzbfile = False if (nzbfile): nzbname = str(nzbtitle) + '.nzb' nzbpath = os.path.join(lazylibrarian.BLACKHOLEDIR, nzbname) try: f = open(nzbpath, 'w') f.write(nzbfile) f.close() logger.info('NZB file saved to: ' + nzbpath) download = True try: os.chmod(nzbpath, 0777) except Exception, e: logger.info("Could not chmod path: " + str(file2)) except Exception, e: logger.error('%s not writable, NZB not saved. Error: %s' % (nzbpath, e)) download = False
def _findBook(self, **kwargs): if 'name' not in kwargs: self.data = 'Missing parameter: name' return myDB = database.DBConnection() if lazylibrarian.BOOK_API == "GoogleBooks": GB = GoogleBooks(kwargs['name']) queue = Queue.Queue() search_api = threading.Thread(target=GB.find_results, name='API-GBRESULTS', args=[kwargs['name'], queue]) search_api.start() elif lazylibrarian.BOOK_API == "GoodReads": queue = Queue.Queue() GR = GoodReads(kwargs['name']) search_api = threading.Thread(target=GR.find_results, name='API-GRRESULTS', args=[kwargs['name'], queue]) search_api.start() search_api.join() self.data = queue.get()
def _writeAllOPF(self, **kwargs): myDB = database.DBConnection() books = myDB.select( 'select BookID from books where BookFile is not null') counter = 0 if books: for book in books: bookid = book['BookID'] if 'refresh' in kwargs: self._writeOPF(id=bookid, refresh=True) else: self._writeOPF(id=bookid) try: if self.data[1] is True: counter += 1 except IndexError: counter = counter self.data = 'Updated opf for %s book%s' % (counter, plural(counter))
def setAllBookAuthors(): myDB = database.DBConnection() myDB.action('drop table if exists bookauthors') myDB.action('create table bookauthors (AuthorID TEXT, BookID TEXT, Role TEXT, UNIQUE (AuthorID, BookID, Role))') books = myDB.select('SELECT AuthorID,BookID from books') for item in books: myDB.action('insert into bookauthors (AuthorID, BookID, Role) values (?, ?, ?)', (item['AuthorID'], item['BookID'], ''), suppress='UNIQUE') totalauthors = 0 totalrefs = 0 books = myDB.select('select bookid,bookname,authorid from books where workpage is not null and workpage != ""') for book in books: newauthors, newrefs = setBookAuthors(book) totalauthors += newauthors totalrefs += newrefs msg = "Added %s new authors to database, %s new bookauthors" % (totalauthors, totalrefs) logger.debug(msg) return totalauthors, totalrefs
def searchForBook(self, bookid=None, action=None, **args): myDB = database.DBConnection() # find book bookdata = myDB.select("SELECT * from books WHERE BookID='%s'" % bookid) if bookdata: AuthorName = bookdata[0]["AuthorName"]; # start searchthreads books = [] books.append({"bookid": bookid}) mags=False threading.Thread(target=searchbook, args=[books, mags]).start() logger.debug("Searching for book with id: " + str(bookid)); if AuthorName: raise cherrypy.HTTPRedirect("authorPage?AuthorName=%s" % AuthorName)