mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-30 23:03:02 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/master'
This commit is contained in:
		| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| from cps import db, ub | ||||
| from cps import config | ||||
| from flask import current_app as app | ||||
|  | ||||
| import smtplib | ||||
| import sys | ||||
| @@ -29,19 +30,17 @@ def update_download(book_id, user_id): | ||||
| def make_mobi(book_id): | ||||
|     kindlegen = os.path.join(config.MAIN_DIR, "vendor", "kindlegen") | ||||
|     if not os.path.exists(kindlegen): | ||||
|         print "make_mobie: kindlegen binary not found in: %s" % kindlegen | ||||
|         app.logger.error("make_mobi: kindlegen binary not found in: %s" % kindlegen) | ||||
|         return None | ||||
|     book = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||
|     data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == 'EPUB').first() | ||||
|     if not data: | ||||
|         print "make_mobie: epub format not found for book id: %d" % book_id | ||||
|         app.logger.error("make_mobi: epub format not found for book id: %d" % book_id) | ||||
|         return None | ||||
|  | ||||
|     file_path = os.path.join(config.DB_ROOT, book.path, data.name) | ||||
|  | ||||
|     # print os.path.getsize(file_path + ".epub") | ||||
|     if os.path.exists(file_path + ".epub"): | ||||
|         # print u"conversion started for %s" % book.title | ||||
|         check = subprocess.call([kindlegen, file_path + ".epub"], stdout=subprocess.PIPE) | ||||
|         if not check or check < 2: | ||||
|             book.data.append(db.Data( | ||||
| @@ -53,15 +52,14 @@ def make_mobi(book_id): | ||||
|             db.session.commit() | ||||
|             return file_path + ".mobi" | ||||
|         else: | ||||
|             print "make_mobie: kindlegen failed to convert book" | ||||
|             app.logger.error("make_mobi: kindlegen failed with error while converting book") | ||||
|             return None | ||||
|     else: | ||||
|         print "make_mobie: epub not found: " + file_path + ".epub" | ||||
|         app.logger.error("make_mobie: epub not found: %s.epub" % file_path) | ||||
|         return None | ||||
|  | ||||
| def send_mail(book_id, kindle_mail): | ||||
|     '''Send email with attachments''' | ||||
|  | ||||
|     is_mobi = False | ||||
|     is_azw = False | ||||
|     is_azw3 = False | ||||
| @@ -73,14 +71,12 @@ def send_mail(book_id, kindle_mail): | ||||
|     msg = MIMEMultipart() | ||||
|     msg['From'] = settings["mail_from"] | ||||
|     msg['To'] = kindle_mail | ||||
|     msg['Subject'] = 'Sent to Kindle' | ||||
|     msg['Subject'] = 'Send to Kindle' | ||||
|     text = 'This email has been sent via calibre web.' | ||||
|     msg.attach(MIMEText(text)) | ||||
|  | ||||
|     use_ssl = settings.get('mail_use_ssl', 0) | ||||
|  | ||||
|     print "use ssl: %d" % use_ssl | ||||
|  | ||||
|     # attach files | ||||
|         #msg.attach(self.get_attachment(file_path)) | ||||
|  | ||||
| @@ -92,24 +88,15 @@ def send_mail(book_id, kindle_mail): | ||||
|     for entry in data: | ||||
|         if entry.format == "MOBI": | ||||
|             formats["mobi"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".mobi") | ||||
|         if entry.format == "AZW": | ||||
|             formats["azw"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".azw") | ||||
|         if entry.format == "AZW3": | ||||
|             formats["azw3"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".azw3") | ||||
|         if entry.format == "EPUB": | ||||
|             formats["epub"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".epub") | ||||
|         if entry.format == "PDF": | ||||
|             formats["pdf"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".pdf") | ||||
|  | ||||
|     if len(formats) == 0: | ||||
|         print "no formats found" | ||||
|         return "Could not find any formats that can be send by email" | ||||
|         return "Could not find any formats suitable for sending by email" | ||||
|  | ||||
|     if 'azw3' in formats: | ||||
|         msg.attach(get_attachment(formats['azw3'])) | ||||
|     elif 'azw' in formats: | ||||
|         msg.attach(get_attachment(formats['azw'])) | ||||
|     elif 'mobi' in formats: | ||||
|     if 'mobi' in formats: | ||||
|         msg.attach(get_attachment(formats['mobi'])) | ||||
|     elif 'epub' in formats: | ||||
|         filepath = make_mobi(book.id) | ||||
| @@ -120,7 +107,7 @@ def send_mail(book_id, kindle_mail): | ||||
|     elif 'pdf' in formats: | ||||
|         msg.attach(get_attachment(formats['pdf'])) | ||||
|     else: | ||||
|         return "Could not find any formats that can be send by email" | ||||
|         return "Could not find any formats suitable for sending by email" | ||||
|  | ||||
|     # convert MIME message to string | ||||
|     fp = StringIO() | ||||
| @@ -141,9 +128,9 @@ def send_mail(book_id, kindle_mail): | ||||
|         mailserver.login(settings["mail_login"], settings["mail_password"]) | ||||
|         mailserver.sendmail(settings["mail_login"], kindle_mail, msg) | ||||
|         mailserver.quit() | ||||
|     except smtplib.SMTPException: | ||||
|         traceback.print_exc() | ||||
|         return "Error communicating with the mail server, please check the logs for details." | ||||
|     except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException), e: | ||||
|         app.logger.error(traceback.print_exc()) | ||||
|         return "Failed to send mail: %s" % str(e) | ||||
|  | ||||
|     return None | ||||
|  | ||||
|   | ||||
| @@ -8,9 +8,9 @@ a{color: #45b29d}a:hover{color: #444;} | ||||
| .container-fluid img{display:block;max-width:100%;height:auto} | ||||
| .container-fluid .discover{margin-bottom:50px} | ||||
| .container-fluid .new-books{border-top:1px solid #ccc}.container-fluid .new-books h2{margin:50px 0 0 0} | ||||
| .container-fluid .book{margin-top:20px}.container-fluid .book .cover{height:225px;position:relative}.container-fluid .book .cover img{border:1px solid #ccc;border-radius:5px;box-sizeing:border-box;height:100%;bottom:0;position:absolute} | ||||
| .container-fluid .book{margin-top:20px}.container-fluid .book .cover{height:225px;position:relative}.container-fluid .book .cover img{border:3px solid #fff;border-radius:5px;box-sizeing:border-box;height:100%;bottom:0;position:absolute;-webkit-box-shadow: 0 5px 8px -6px #777;-moz-box-shadow: 0 5px 8px -6px #777;box-shadow: 0 5px 8px -6px #777;} | ||||
| .container-fluid .book .meta{margin-top:10px}.container-fluid .book .meta p{margin:0} | ||||
| .container-fluid .book .meta .title{font-weight:bold;font-size:16px;color:#444} | ||||
| .container-fluid .book .meta .title{font-weight:bold;font-size:15px;color:#444} | ||||
| .container-fluid .book .meta .author{font-size:12px;color:#999} | ||||
| .container-fluid .book .meta .rating{margin-top:5px}.rating .glyphicon-star{color:#999}.rating .glyphicon-star.good{color:#45b29d} | ||||
| .navbar-brand{font-family: 'Grand Hotel', cursive; font-size: 35px; color: #45b29d !important;} | ||||
| @@ -20,3 +20,11 @@ a{color: #45b29d}a:hover{color: #444;} | ||||
| span.glyphicon.glyphicon-tags {padding-right: 5px;color: #999;vertical-align: text-top;} | ||||
| .book-meta {padding-bottom: 20px;} | ||||
| .book-meta .tags a {display: inline;} | ||||
| .container-fluid .single .cover img { | ||||
|     border: 3px solid #fff; | ||||
|     border-radius: 5px; | ||||
|     box-sizeing: border-box; | ||||
|     -webkit-box-shadow: 0 5px 8px -6px #777; | ||||
|     -moz-box-shadow: 0 5px 8px -6px #777; | ||||
|     box-shadow: 0 5px 8px -6px #777; | ||||
| } | ||||
| @@ -126,7 +126,6 @@ | ||||
|       {% endif %} | ||||
|  | ||||
|       {% if g.user.role %} | ||||
|       </br> | ||||
|       <div class="btn-toolbar" role="toolbar"> | ||||
|         <div class="btn-group" role="group" aria-label="Edit/Delete book"> | ||||
|           <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> Edit metadata</a> | ||||
|   | ||||
| @@ -8,11 +8,11 @@ | ||||
|       <input type="text" class="form-control" name="mail_server" id="mail_server" value="{{content.mail_server}}"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="mail_port">SMTP port (usually 25 for unencrypted and 587 for StartTLS)</label> | ||||
|       <label for="mail_port">SMTP port (usually 25 for plain SMTP and 587 for SSL)</label> | ||||
|       <input type="text" class="form-control" name="mail_port" id="mail_port" value="{{content.mail_port}}"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="mail_use_ssl">Server requires encryption (StartTLS)</label> | ||||
|       <label for="mail_use_ssl">Server uses SSL (StartTLS)</label> | ||||
|       <input type="checkbox" name="mail_use_ssl" id="mail_use_ssl" {% if content.mail_use_ssl %}checked{% endif %}> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|   | ||||
| @@ -25,7 +25,7 @@ | ||||
|     <tr> | ||||
|         <th>SMTP hostname</th> | ||||
|         <th>SMTP port</th> | ||||
|         <th>Server requires SSL</th> | ||||
|         <th>SSL</th> | ||||
|         <th>SMTP login</th> | ||||
|         <th>SMTP password</th> | ||||
|         <th>From mail</th> | ||||
|   | ||||
							
								
								
									
										40
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -2,6 +2,8 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import mimetypes | ||||
| import logging | ||||
| import sys | ||||
| mimetypes.add_type('application/xhtml+xml','.xhtml') | ||||
| from flask import Flask, render_template, session, request, Response, redirect, url_for, send_from_directory, make_response, g, flash, abort | ||||
| from cps import db, config, ub, helper | ||||
| @@ -21,6 +23,15 @@ import json | ||||
|  | ||||
| app = (Flask(__name__)) | ||||
|  | ||||
| # Log only in production mode. | ||||
| #if not app.debug: | ||||
| file_handler = logging.StreamHandler(sys.stdout) | ||||
| file_handler.setLevel(logging.INFO) | ||||
| app.logger.addHandler(file_handler) | ||||
| app.logger_name = 'calibre web' | ||||
| app.logger.setLevel(logging.INFO) | ||||
| app.logger.info('Starting Calibre Web...') | ||||
|  | ||||
| Principal(app) | ||||
|  | ||||
| lm = LoginManager(app) | ||||
| @@ -42,8 +53,6 @@ def load_user_from_header(header_val): | ||||
|         header_val = base64.b64decode(header_val) | ||||
|         basic_username = header_val.split(':')[0] | ||||
|         basic_password = header_val.split(':')[1] | ||||
|         #print basic_username | ||||
|         #print basic_password | ||||
|     except TypeError: | ||||
|         pass | ||||
|     user = ub.session.query(ub.User).filter(ub.User.nickname == basic_username).first() | ||||
| @@ -213,14 +222,7 @@ def get_opds_download_link(book_id, format): | ||||
|         file_name = author+'-'+file_name | ||||
|     file_name = helper.get_valid_filename(file_name) | ||||
|     response = make_response(send_from_directory(os.path.join(config.DB_ROOT, book.path), data.name + "." +format)) | ||||
|     #response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (data.name, format) | ||||
|     response.headers["Content-Disposition"] = \ | ||||
|         "attachment; " \ | ||||
|         "filename={utf_filename}.{suffix};" \ | ||||
|         "filename*=UTF-8''{utf_filename}.{suffix}".format( | ||||
|         utf_filename=file_name.encode('utf-8'), | ||||
|         suffix=format | ||||
|     ) | ||||
|     response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (data.name, format) | ||||
|     return response | ||||
|      | ||||
| @app.route("/get_authors_json", methods = ['GET', 'POST']) | ||||
| @@ -247,12 +249,6 @@ def index(page): | ||||
| @app.route('/hot/page/<int:page>') | ||||
| def hot_books(page): | ||||
|     random = db.session.query(db.Books).filter(false()) | ||||
|     # if page == 1: | ||||
|     #     entries = db.session.query(db.Books).filter(db.Books.ratings.any(db.Ratings.rating > 9)).order_by(db.Books.last_modified.desc()).limit(config.NEWEST_BOOKS) | ||||
|     # else: | ||||
|     #     off = int(int(config.NEWEST_BOOKS) * (page - 1)) | ||||
|     #     entries = db.session.query(db.Books).filter(db.Books.ratings.any(db.Ratings.rating > 9)).order_by(db.Books.last_modified.desc()).offset(60).limit(config.NEWEST_BOOKS) | ||||
|  | ||||
|     off = int(int(6) * (page - 1)) | ||||
|     all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id) | ||||
|     hot_books = all_books.offset(off).limit(config.NEWEST_BOOKS) | ||||
| @@ -379,7 +375,6 @@ def get_download_link(book_id, format): | ||||
|         file_name = author+'-'+file_name | ||||
|     file_name = helper.get_valid_filename(file_name) | ||||
|     response = make_response(send_from_directory(os.path.join(config.DB_ROOT, book.path), data.name + "." +format)) | ||||
|     #response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (file_name, format) | ||||
|     response.headers["Content-Disposition"] = \ | ||||
|         "attachment; " \ | ||||
|         "filename={utf_filename}.{suffix};" \ | ||||
| @@ -553,7 +548,6 @@ def profile(): | ||||
|         downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) | ||||
|     if request.method == "POST": | ||||
|         to_save = request.form.to_dict() | ||||
|         #print to_save | ||||
|         if to_save["password"]: | ||||
|             content.password = generate_password_hash(to_save["password"]) | ||||
|         if to_save["kindle_mail"] and to_save["kindle_mail"] != content.kindle_mail: | ||||
| @@ -669,7 +663,6 @@ def edit_book(book_id): | ||||
|     book = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||
|     if request.method == 'POST': | ||||
|         to_save = request.form.to_dict() | ||||
|         #print to_save | ||||
|         book.title = to_save["book_title"] | ||||
|          | ||||
|         is_author = db.session.query(db.Authors).filter(db.Authors.name.like('%' + to_save["author_name"].strip() + '%')).first() | ||||
| @@ -701,7 +694,6 @@ def edit_book(book_id): | ||||
|  | ||||
|         for tag in to_save["tags"].split(","): | ||||
|             if tag.strip(): | ||||
|                 #print tag | ||||
|                 is_tag = db.session.query(db.Tags).filter(db.Tags.name.like('%' + tag.strip() + '%')).first() | ||||
|                 if is_tag: | ||||
|                     book.tags.append(is_tag) | ||||
| @@ -729,11 +721,3 @@ def edit_book(book_id): | ||||
|             return render_template('edit_book.html', book=book) | ||||
|     else: | ||||
|         return render_template('edit_book.html', book=book) | ||||
|  | ||||
| # @app.route('/admin/delete/<int:book_id>') | ||||
| # def delete_book(book_id): | ||||
| #     to_delete = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||
| #     print to_delete | ||||
| #     db.session.delete(to_delete) | ||||
| #     db.session.commit() | ||||
| #     return redirect(url_for('index')) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Cervinko Cera
					Cervinko Cera