//  [python]
def edit_book(book_id):
    modif_date = False

    # create the function for sorting...
    try:
        calibre_db.update_title_sort(config)
    except sqliteOperationalError as e:
        log.error_or_exception(e)
        calibre_db.session.rollback()

    # Show form
    if request.method != 'POST':
        return render_edit_book(book_id)

    book = calibre_db.get_filtered_book(book_id, allow_show_archived=True)

    # Book not found
    if not book:
        flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), category="error")
        return redirect(url_for("web.index"))

    meta = upload_single_file(request, book, book_id)
    if upload_cover(request, book) is True:
        book.has_cover = 1
        modif_date = True
    try:
        to_save = request.form.to_dict()
        merge_metadata(to_save, meta)
        # Update book
        edited_books_id = None

        # handle book title
        title_change = handle_title_on_edit(book, to_save["book_title"])

        input_authors, authorchange, renamed = handle_author_on_edit(book, to_save["author_name"])
        if authorchange or title_change:
            edited_books_id = book.id
            modif_date = True

        if config.config_use_google_drive:
            gdriveutils.updateGdriveCalibreFromLocal()

        error = False
        if edited_books_id:
            error = helper.update_dir_structure(edited_books_id, config.config_calibre_dir, input_authors[0],
                                               renamed_author=renamed)

        if not error:
            if "cover_url" in to_save:
                if to_save["cover_url"]:
                    if not current_user.role_upload():
                        calibre_db.session.rollback()
                        return "", 403
                    if to_save["cover_url"].endswith('/static/generic_cover.jpg'):
                        book.has_cover = 0
                    else:
                        result, error = helper.save_cover_from_url(to_save["cover_url"], book.path)
                        if result is True:
                            book.has_cover = 1
                            modif_date = True
                        else:
                            flash(error, category="error")

            # Add default series_index to book
            modif_date |= edit_book_series_index(to_save["series_index"], book)
            # Handle book comments/description
            modif_date |= edit_book_comments(Markup(to_save['description']).unescape(), book)
            # Handle identifiers
            input_identifiers = identifier_list(to_save, book)
            modification, warning = modify_identifiers(input_identifiers, book.identifiers, calibre_db.session)
            if warning:
                flash(_("Identifiers are not Case Sensitive, Overwriting Old Identifier"), category="warning")
            modif_date |= modification
            # Handle book tags
            modif_date |= edit_book_tags(to_save['tags'], book)
            # Handle book series
            modif_date |= edit_book_series(to_save["series"], book)
            # handle book publisher
            modif_date |= edit_book_publisher(to_save['publisher'], book)
            # handle book languages
            modif_date |= edit_book_languages(to_save['languages'], book)
            # handle book ratings
            modif_date |= edit_book_ratings(to_save, book)
            # handle cc data
            modif_date |= edit_all_cc_data(book_id, book, to_save)

            if to_save["pubdate"]:
                try:
                    book.pubdate = datetime.strptime(to_save["pubdate"], "%Y-%m-%d")
                except ValueError:
                    book.pubdate = db.Books.DEFAULT_PUBDATE
            else:
                book.pubdate = db.Books.DEFAULT_PUBDATE

            if modif_date:
                book.last_modified = datetime.utcnow()
                kobo_sync_status.remove_synced_book(edited_books_id, all=True)

            calibre_db.session.merge(book)
            calibre_db.session.commit()
            if config.config_use_google_drive:
                gdriveutils.updateGdriveCalibreFromLocal()
            if "detail_view" in to_save:
                return redirect(url_for('web.show_book', book_id=book.id))
            else:
                flash(_("Metadata successfully updated"), category="success")
                return render_edit_book(book_id)
        else:
            calibre_db.session.rollback()
            flash(error, category="error")
            return render_edit_book(book_id)
    except ValueError as e:
        calibre_db.session.rollback()
        flash(str(e), category="error")
        return redirect(url_for('web.show_book', book_id=book.id))
    except (OperationalError, IntegrityError) as e:
        log.error_or_exception("Database error: {}".format(e))
        calibre_db.session.rollback()
        flash(_(u"Database error: %(error)s.", error=e.orig), category="error")
        return redirect(url_for('web.show_book', book_id=book.id))
    except Exception as ex:
        log.error_or_exception(ex)
        calibre_db.session.rollback()
        flash(_("Error editing book, please check logfile for details"), category="error")
        return redirect(url_for('web.show_book', book_id=book.id))