jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def clean_author_database(renamed_author, calibre_path="", local_book=None, gdrive=None):
    valid_filename_authors = [get_valid_filename(r, chars=96) for r in renamed_author]
    for r in renamed_author:
        if local_book:
            all_books = [local_book]
        else:
            all_books = calibre_db.session.query(db.Books) \
                .filter(db.Books.authors.any(db.Authors.name == r)).all()
        for book in all_books:
            book_author_path = book.path.split('/')[0]
            if book_author_path in valid_filename_authors or local_book:
                new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first()
                all_new_authordir = get_valid_filename(new_author.name, chars=96)
                all_titledir = book.path.split('/')[1]
                all_new_path = os.path.join(calibre_path, all_new_authordir, all_titledir)
                all_new_name = get_valid_filename(book.title, chars=42) + ' - ' \
                    + get_valid_filename(new_author.name, chars=42)
                # change location in database to new author/title path
                book.path = os.path.join(all_new_authordir, all_titledir).replace('\\', '/')
                for file_format in book.data:
                    if not gdrive:
                        shutil.move(os.path.normcase(os.path.join(all_new_path,
                                                                  file_format.name + '.' + file_format.format.lower())),
                                    os.path.normcase(os.path.join(all_new_path,
                                                                  all_new_name + '.' + file_format.format.lower())))
                    else:
                        g_file = gd.getFileFromEbooksFolder(all_new_path,
                                                            file_format.name + '.' + file_format.format.lower())
                        if g_file:
                            gd.moveGdriveFileRemote(g_file, all_new_name + u'.' + file_format.format.lower())
                            gd.updateDatabaseOnEdit(g_file['id'], all_new_name + u'.' + file_format.format.lower())
                        else:
                            log.error("File {} not found on gdrive"
                                      .format(all_new_path, file_format.name + '.' + file_format.format.lower()))
                    file_format.name = all_new_name
//  [python]
def clean_author_database(renamed_author, calibre_path="", local_book=None, gdrive=None):
    valid_filename_authors = [get_valid_filename(r, chars=96) for r in renamed_author]
    for r in renamed_author:
        if local_book:
            all_books = [local_book]
        else:
            all_books = calibre_db.session.query(db.Books) \
                .filter(db.Books.authors.any(db.Authors.name == r)).all()
        for book in all_books:
            book_author_path = book.path.split('/')[0]
            if book_author_path in valid_filename_authors or local_book:
                new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first()
                all_new_authordir = get_valid_filename(new_author.name, chars=96)
                all_titledir = book.path.split('/')[1]
                all_new_path = os.path.join(calibre_path, all_new_authordir, all_titledir)
                all_new_name = get_valid_filename(book.title, chars=42) + ' - ' \
                               + get_valid_filename(new_author.name, chars=42)
                # change location in database to new author/title path
                book.path = os.path.join(all_new_authordir, all_titledir).replace('\\', '/')
                for file_format in book.data:
                    if not gdrive:
                        shutil.move(os.path.normcase(os.path.join(all_new_path,
                                                                  file_format.name + '.' + file_format.format.lower())),
                            os.path.normcase(os.path.join(all_new_path,
                                                          all_new_name + '.' + file_format.format.lower())))
                    else:
                        gFile = gd.getFileFromEbooksFolder(all_new_path,
                                                           file_format.name + '.' + file_format.format.lower())
                        if gFile:
                            gd.moveGdriveFileRemote(gFile, all_new_name + u'.' + file_format.format.lower())
                            gd.updateDatabaseOnEdit(gFile['id'], all_new_name + u'.' + file_format.format.lower())
                        else:
                            log.error("File {} not found on gdrive"
                                      .format(all_new_path, file_format.name + '.' + file_format.format.lower()))
                    file_format.name = all_new_name
//  [python]
def check_send_to_kindle_with_converter(formats):
    bookformats = list()
    if 'EPUB' in formats and 'MOBI' not in formats:
        bookformats.append({'format': 'Mobi',
                            'convert': 1,
                            'text': _('Convert %(orig)s to %(format)s and send to Kindle',
                                      orig='Epub',
                                      format='Mobi')})
    if 'AZW3' in formats and 'MOBI' not in formats:
        bookformats.append({'format': 'Mobi',
                            'convert': 2,
                            'text': _('Convert %(orig)s to %(format)s and send to Kindle',
                                      orig='Azw3',
                                      format='Mobi')})
    return bookformats
//  [python]
def check_send_to_kindle_with_converter(formats):
    bookformats = list()
    if 'EPUB' in formats and 'MOBI' not in formats:
        bookformats.append({'format': 'Mobi',
                            'convert': 1,
                            'text': _('Convert %(orig)s to %(format)s and send to Kindle',
                                      orig='Epub',
                                      format='Mobi')})
    if 'AZW3' in formats and not 'MOBI' in formats:
        bookformats.append({'format': 'Mobi',
                            'convert': 2,
                            'text': _('Convert %(orig)s to %(format)s and send to Kindle',
                                      orig='Azw3',
                                      format='Mobi')})
    return bookformats
//  [python]
def check_unrar(unrar_location):
    if not unrar_location:
        return

    if not os.path.exists(unrar_location):
        return _('Unrar binary file not found')

    try:
        unrar_location = [unrar_location]
        value = process_wait(unrar_location, pattern='UNRAR (.*) freeware')
        if value:
            version = value.group(1)
            log.debug("unrar version %s", version)

    except (OSError, UnicodeDecodeError) as err:
        log.error_or_exception(err)
        return _('Error excecuting UnRar')
//  [python]
def check_unrar(unrarLocation):
    if not unrarLocation:
        return

    if not os.path.exists(unrarLocation):
        return _('Unrar binary file not found')

    try:
        unrarLocation = [unrarLocation]
        value = process_wait(unrarLocation, pattern='UNRAR (.*) freeware')
        if value:
            version = value.group(1)
            log.debug("unrar version %s", version)

    except (OSError, UnicodeDecodeError) as err:
        log.error_or_exception(err)
        return _('Error excecuting UnRar')
//  [python]
def delete_book_gdrive(book, book_format):
    error = None
    if book_format:
        name = ''
        for entry in book.data:
            if entry.format.upper() == book_format:
                name = entry.name + '.' + book_format
        g_file = gd.getFileFromEbooksFolder(book.path, name)
    else:
        g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), book.path.split('/')[1])
    if g_file:
        gd.deleteDatabaseEntry(g_file['id'])
        g_file.Trash()
    else:
        error = _(u'Book path %(path)s not found on Google Drive', path=book.path)  # file not found

    return error is None, error
//  [python]
def delete_book_gdrive(book, book_format):
    error = None
    if book_format:
        name = ''
        for entry in book.data:
            if entry.format.upper() == book_format:
                name = entry.name + '.' + book_format
        gFile = gd.getFileFromEbooksFolder(book.path, name)
    else:
        gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), book.path.split('/')[1])
    if gFile:
        gd.deleteDatabaseEntry(gFile['id'])
        gFile.Trash()
    else:
        error = _(u'Book path %(path)s not found on Google Drive', path=book.path)  # file not found

    return error is None, error
//  [python]
def delete_book_file(book, calibrepath, book_format=None):
    # check that path is 2 elements deep, check that target path has no subfolders
    if book.path.count('/') == 1:
        path = os.path.join(calibrepath, book.path)
        if book_format:
            for file in os.listdir(path):
                if file.upper().endswith("."+book_format):
                    os.remove(os.path.join(path, file))
            return True, None
        else:
            if os.path.isdir(path):
                try:
                    for root, folders, files in os.walk(path):
                        for f in files:
                            os.unlink(os.path.join(root, f))
                        if len(folders):
                            log.warning("Deleting book {} failed, path {} has subfolders: {}".format(book.id,
                                        book.path, folders))
                            return True, _("Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s",
                                           id=book.id,
                                           path=book.path)
                    shutil.rmtree(path)
                except (IOError, OSError) as ex:
                    log.error("Deleting book %s failed: %s", book.id, ex)
                    return False, _("Deleting book %(id)s failed: %(message)s", id=book.id, message=ex)
                authorpath = os.path.join(calibrepath, os.path.split(book.path)[0])
                if not os.listdir(authorpath):
                    try:
                        shutil.rmtree(authorpath)
                    except (IOError, OSError) as ex:
                        log.error("Deleting authorpath for book %s failed: %s", book.id, ex)
                return True, None

    log.error("Deleting book %s from database only, book path in database not valid: %s",
              book.id, book.path)
    return True, _("Deleting book %(id)s from database only, book path in database not valid: %(path)s",
                   id=book.id,
                   path=book.path)
//  [python]
def delete_book_file(book, calibrepath, book_format=None):
    # check that path is 2 elements deep, check that target path has no subfolders
    if book.path.count('/') == 1:
        path = os.path.join(calibrepath, book.path)
        if book_format:
            for file in os.listdir(path):
                if file.upper().endswith("."+book_format):
                    os.remove(os.path.join(path, file))
            return True, None
        else:
            if os.path.isdir(path):
                try:
                    for root, folders, files in os.walk(path):
                        for f in files:
                            os.unlink(os.path.join(root, f))
                        if len(folders):
                            log.warning("Deleting book {} failed, path {} has subfolders: {}".format(book.id,
                                        book.path, folders))
                            return True, _("Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s",
                                           id=book.id,
                                           path=book.path)
                    shutil.rmtree(path)
                except (IOError, OSError) as e:
                    log.error("Deleting book %s failed: %s", book.id, e)
                    return False, _("Deleting book %(id)s failed: %(message)s", id=book.id, message=e)
                authorpath = os.path.join(calibrepath, os.path.split(book.path)[0])
                if not os.listdir(authorpath):
                    try:
                        shutil.rmtree(authorpath)
                    except (IOError, OSError) as e:
                        log.error("Deleting authorpath for book %s failed: %s", book.id, e)
                return True, None

    log.error("Deleting book %s from database only, book path in database not valid: %s",
              book.id, book.path)
    return True, _("Deleting book %(id)s from database only, book path in database not valid: %(path)s",
                   id=book.id,
                   path=book.path)
//  [python]
def get_cc_columns(filter_config_custom_read=False):
    tmpcc = calibre_db.session.query(db.CustomColumns)\
        .filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)).all()
    cc = []
    r = None
    if config.config_columns_to_ignore:
        r = re.compile(config.config_columns_to_ignore)

    for col in tmpcc:
        if filter_config_custom_read and config.config_read_column and config.config_read_column == col.id:
            continue
        if r and r.match(col.name):
            continue
        cc.append(col)

    return cc
//  [python]
def get_cc_columns(filter_config_custom_read=False):
    tmpcc = calibre_db.session.query(db.Custom_Columns)\
        .filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
    cc = []
    r = None
    if config.config_columns_to_ignore:
        r = re.compile(config.config_columns_to_ignore)

    for col in tmpcc:
        if filter_config_custom_read and config.config_read_column and config.config_read_column == col.id:
            continue
        if r and r.match(col.name):
            continue
        cc.append(col)

    return cc
//  [python]
def edit_book_read_status(book_id, read_status=None):
    if not config.config_read_column:
        book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id),
                                                         ub.ReadBook.book_id == book_id)).first()
        if book:
            if read_status is None:
                if book.read_status == ub.ReadBook.STATUS_FINISHED:
                    book.read_status = ub.ReadBook.STATUS_UNREAD
                else:
                    book.read_status = ub.ReadBook.STATUS_FINISHED
            else:
                book.read_status = ub.ReadBook.STATUS_FINISHED if read_status else ub.ReadBook.STATUS_UNREAD
        else:
            read_book = ub.ReadBook(user_id=current_user.id, book_id=book_id)
            read_book.read_status = ub.ReadBook.STATUS_FINISHED
            book = read_book
        if not book.kobo_reading_state:
            kobo_reading_state = ub.KoboReadingState(user_id=current_user.id, book_id=book_id)
            kobo_reading_state.current_bookmark = ub.KoboBookmark()
            kobo_reading_state.statistics = ub.KoboStatistics()
            book.kobo_reading_state = kobo_reading_state
        ub.session.merge(book)
        ub.session_commit("Book {} readbit toggled".format(book_id))
    else:
        try:
            calibre_db.update_title_sort(config)
            book = calibre_db.get_filtered_book(book_id)
            read_status = getattr(book, 'custom_column_' + str(config.config_read_column))
            if len(read_status):
                if read_status is None:
                    read_status[0].value = not read_status[0].value
                else:
                    read_status[0].value = read_status is True
                calibre_db.session.commit()
            else:
                cc_class = db.cc_classes[config.config_read_column]
                new_cc = cc_class(value=read_status or 1, book=book_id)
                calibre_db.session.add(new_cc)
                calibre_db.session.commit()
        except (KeyError, AttributeError):
            log.error(u"Custom Column No.%d is not existing in calibre database", config.config_read_column)
            return "Custom Column No.{} is not existing in calibre database".format(config.config_read_column)
        except (OperationalError, InvalidRequestError) as ex:
            calibre_db.session.rollback()
            log.error(u"Read status could not set: {}".format(ex))
            return _("Read status could not set: {}".format(ex.orig))
    return ""
//  [python]
def edit_book_read_status(book_id, read_status=None):
    if not config.config_read_column:
        book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id),
                                                         ub.ReadBook.book_id == book_id)).first()
        if book:
            if read_status is None:
                if book.read_status == ub.ReadBook.STATUS_FINISHED:
                    book.read_status = ub.ReadBook.STATUS_UNREAD
                else:
                    book.read_status = ub.ReadBook.STATUS_FINISHED
            else:
                book.read_status = ub.ReadBook.STATUS_FINISHED if read_status else ub.ReadBook.STATUS_UNREAD
        else:
            readBook = ub.ReadBook(user_id=current_user.id, book_id = book_id)
            readBook.read_status = ub.ReadBook.STATUS_FINISHED
            book = readBook
        if not book.kobo_reading_state:
            kobo_reading_state = ub.KoboReadingState(user_id=current_user.id, book_id=book_id)
            kobo_reading_state.current_bookmark = ub.KoboBookmark()
            kobo_reading_state.statistics = ub.KoboStatistics()
            book.kobo_reading_state = kobo_reading_state
        ub.session.merge(book)
        ub.session_commit("Book {} readbit toggled".format(book_id))
    else:
        try:
            calibre_db.update_title_sort(config)
            book = calibre_db.get_filtered_book(book_id)
            read_status = getattr(book, 'custom_column_' + str(config.config_read_column))
            if len(read_status):
                if read_status is None:
                    read_status[0].value = not read_status[0].value
                else:
                    read_status[0].value = read_status is True
                calibre_db.session.commit()
            else:
                cc_class = db.cc_classes[config.config_read_column]
                new_cc = cc_class(value=read_status or 1, book=book_id)
                calibre_db.session.add(new_cc)
                calibre_db.session.commit()
        except (KeyError, AttributeError):
            log.error(u"Custom Column No.%d is not existing in calibre database", config.config_read_column)
            return "Custom Column No.{} is not existing in calibre database".format(config.config_read_column)
        except (OperationalError, InvalidRequestError) as e:
            calibre_db.session.rollback()
            log.error(u"Read status could not set: {}".format(e))
            return _("Read status could not set: {}".format(e.orig))
    return ""
//  [python]
def get_valid_filename(value, replace_whitespace=True, chars=128):
    """
    Returns the given string converted to a string that can be used for a clean
    filename. Limits num characters to 128 max.
    """
    if value[-1:] == u'.':
        value = value[:-1]+u'_'
    value = value.replace("/", "_").replace(":", "_").strip('\0')
    if config.config_unicode_filename:
        value = (unidecode.unidecode(value))
    if replace_whitespace:
        #  *+:\"/<>? are replaced by _
        value = re.sub(r'[*+:\\\"/<>?]+', u'_', value, flags=re.U)
        # pipe has to be replaced with comma
        value = re.sub(r'[|]+', u',', value, flags=re.U)
    value = value[:chars].strip()
    if not value:
        raise ValueError("Filename cannot be empty")
    return value
//  [python]
def get_valid_filename(value, replace_whitespace=True, chars=128):
    """
    Returns the given string converted to a string that can be used for a clean
    filename. Limits num characters to 128 max.
    """
    if value[-1:] == u'.':
        value = value[:-1]+u'_'
    value = value.replace("/", "_").replace(":", "_").strip('\0')
    if use_unidecode:
        if config.config_unicode_filename:
            value = (unidecode.unidecode(value))
    else:
        value = value.replace(u'§', u'SS')
        value = value.replace(u'ß', u'ss')
        value = unicodedata.normalize('NFKD', value)
        re_slugify = re.compile(r'[\W\s-]', re.UNICODE)
        value = re_slugify.sub('', value)
    if replace_whitespace:
        #  *+:\"/<>? are replaced by _
        value = re.sub(r'[*+:\\\"/<>?]+', u'_', value, flags=re.U)
        # pipe has to be replaced with comma
        value = re.sub(r'[|]+', u',', value, flags=re.U)
    value = value[:chars].strip()
    if not value:
        raise ValueError("Filename cannot be empty")
    return value
//  [python]
def save_cover(img, book_path):
    content_type = img.headers.get('content-type')

    if use_IM:
        if content_type not in ('image/jpeg', 'image/png', 'image/webp', 'image/bmp'):
            log.error("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
            return False, _("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
        # convert to jpg because calibre only supports jpg
        if content_type != 'image/jpg':
            try:
                if hasattr(img, 'stream'):
                    imgc = Image(blob=img.stream)
                else:
                    imgc = Image(blob=io.BytesIO(img.content))
                imgc.format = 'jpeg'
                imgc.transform_colorspace("rgb")
                img = imgc
            except (BlobError, MissingDelegateError):
                log.error("Invalid cover file content")
                return False, _("Invalid cover file content")
    else:
        if content_type not in 'image/jpeg':
            log.error("Only jpg/jpeg files are supported as coverfile")
            return False, _("Only jpg/jpeg files are supported as coverfile")

    if config.config_use_google_drive:
        tmp_dir = os.path.join(gettempdir(), 'calibre_web')

        if not os.path.isdir(tmp_dir):
            os.mkdir(tmp_dir)
        ret, message = save_cover_from_filestorage(tmp_dir, "uploaded_cover.jpg", img)
        if ret is True:
            gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg').replace("\\", "/"),
                                        os.path.join(tmp_dir, "uploaded_cover.jpg"))
            log.info("Cover is saved on Google Drive")
            return True, None
        else:
            return False, message
    else:
        return save_cover_from_filestorage(os.path.join(config.config_calibre_dir, book_path), "cover.jpg", img)
//  [python]
def save_cover(img, book_path):
    content_type = img.headers.get('content-type')

    if use_IM:
        if content_type not in ('image/jpeg', 'image/png', 'image/webp', 'image/bmp'):
            log.error("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
            return False, _("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
        # convert to jpg because calibre only supports jpg
        if content_type != 'image/jpg':
            try:
                if hasattr(img, 'stream'):
                    imgc = Image(blob=img.stream)
                else:
                    imgc = Image(blob=io.BytesIO(img.content))
                imgc.format = 'jpeg'
                imgc.transform_colorspace("rgb")
                img = imgc
            except (BlobError, MissingDelegateError):
                log.error("Invalid cover file content")
                return False, _("Invalid cover file content")
    else:
        if content_type not in 'image/jpeg':
            log.error("Only jpg/jpeg files are supported as coverfile")
            return False, _("Only jpg/jpeg files are supported as coverfile")

    if config.config_use_google_drive:
        tmp_dir = os.path.join(gettempdir(), 'calibre_web')

        if not os.path.isdir(tmp_dir):
            os.mkdir(tmp_dir)
        ret, message = save_cover_from_filestorage(tmp_dir, "uploaded_cover.jpg", img)
        if ret is True:
            gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg').replace("\\","/"),
                                        os.path.join(tmp_dir, "uploaded_cover.jpg"))
            log.info("Cover is saved on Google Drive")
            return True, None
        else:
            return False, message
    else:
        return save_cover_from_filestorage(os.path.join(config.config_calibre_dir, book_path), "cover.jpg", img)
//  [python]
def rename_all_authors(first_author, renamed_author, calibre_path="", localbook=None, gdrive=False):
    # Create new_author_dir from parameter or from database
    # Create new title_dir from database and add id
    if first_author:
        new_authordir = get_valid_filename(first_author, chars=96)
        for r in renamed_author:
            new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first()
            old_author_dir = get_valid_filename(r, chars=96)
            new_author_rename_dir = get_valid_filename(new_author.name, chars=96)
            if gdrive:
                g_file = gd.getFileFromEbooksFolder(None, old_author_dir)
                if g_file:
                    gd.moveGdriveFolderRemote(g_file, new_author_rename_dir)
            else:
                if os.path.isdir(os.path.join(calibre_path, old_author_dir)):
                    try:
                        old_author_path = os.path.join(calibre_path, old_author_dir)
                        new_author_path = os.path.join(calibre_path, new_author_rename_dir)
                        shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path))
                    except OSError as ex:
                        log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex)
                        log.debug(ex, exc_info=True)
                        return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                                 src=old_author_path, dest=new_author_path, error=str(ex))
    else:
        new_authordir = get_valid_filename(localbook.authors[0].name, chars=96)
    return new_authordir
//  [python]
def rename_all_authors(first_author, renamed_author, calibre_path="", localbook=None, gdrive=False):
    # Create new_author_dir from parameter or from database
    # Create new title_dir from database and add id
    if first_author:
        new_authordir = get_valid_filename(first_author, chars=96)
        for r in renamed_author:
            new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first()
            old_author_dir = get_valid_filename(r, chars=96)
            new_author_rename_dir = get_valid_filename(new_author.name, chars=96)
            if gdrive:
                gFile = gd.getFileFromEbooksFolder(None, old_author_dir)
                if gFile:
                    gd.moveGdriveFolderRemote(gFile, new_author_rename_dir)
            else:
                if os.path.isdir(os.path.join(calibre_path, old_author_dir)):
                    try:
                        old_author_path = os.path.join(calibre_path, old_author_dir)
                        new_author_path = os.path.join(calibre_path, new_author_rename_dir)
                        shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path))
                    except (OSError) as ex:
                        log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex)
                        log.debug(ex, exc_info=True)
                        return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                                 src=old_author_path, dest=new_author_path, error=str(ex))
    else:
        new_authordir = get_valid_filename(localbook.authors[0].name, chars=96)
    return new_authordir
//  [python]
def format_runtime(runtime):
    ret_val = ""
    if runtime.days:
        ret_val = format_unit(runtime.days, 'duration-day', length="long", locale=get_locale()) + ', '
    mins, seconds = divmod(runtime.seconds, 60)
    hours, minutes = divmod(mins, 60)
    # ToDo: locale.number_symbols._data['timeSeparator'] -> localize time separator ?
    if hours:
        ret_val += '{:d}:{:02d}:{:02d}s'.format(hours, minutes, seconds)
    elif minutes:
        ret_val += '{:2d}:{:02d}s'.format(minutes, seconds)
    else:
        ret_val += '{:2d}s'.format(seconds)
    return ret_val
//  [python]
def format_runtime(runtime):
    retVal = ""
    if runtime.days:
        retVal = format_unit(runtime.days, 'duration-day', length="long", locale=get_locale()) + ', '
    mins, seconds = divmod(runtime.seconds, 60)
    hours, minutes = divmod(mins, 60)
    # ToDo: locale.number_symbols._data['timeSeparator'] -> localize time separator ?
    if hours:
        retVal += '{:d}:{:02d}:{:02d}s'.format(hours, minutes, seconds)
    elif minutes:
        retVal += '{:2d}:{:02d}s'.format(minutes, seconds)
    else:
        retVal += '{:2d}s'.format(seconds)
    return retVal
//  [python]
def move_files_on_change(calibre_path, new_authordir, new_titledir, localbook, db_filename, original_filepath, path):
    new_path = os.path.join(calibre_path, new_authordir, new_titledir)
    new_name = get_valid_filename(localbook.title, chars=96) + ' - ' + new_authordir
    try:
        if original_filepath:
            if not os.path.isdir(new_path):
                os.makedirs(new_path)
            shutil.move(os.path.normcase(original_filepath), os.path.normcase(os.path.join(new_path, db_filename)))
            log.debug("Moving title: %s to %s/%s", original_filepath, new_path, new_name)
        else:
            # Check new path is not valid path
            if not os.path.exists(new_path):
                # move original path to new path
                log.debug("Moving title: %s to %s", path, new_path)
                shutil.move(os.path.normcase(path), os.path.normcase(new_path))
            else:  # path is valid copy only files to new location (merge)
                log.info("Moving title: %s into existing: %s", path, new_path)
                # Take all files and subfolder from old path (strange command)
                for dir_name, __, file_list in os.walk(path):
                    for file in file_list:
                        shutil.move(os.path.normcase(os.path.join(dir_name, file)),
                                    os.path.normcase(os.path.join(new_path + dir_name[len(path):], file)))
        # change location in database to new author/title path
        localbook.path = os.path.join(new_authordir, new_titledir).replace('\\', '/')
    except OSError as ex:
        log.error("Rename title from: %s to %s: %s", path, new_path, ex)
        log.debug(ex, exc_info=True)
        return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                 src=path, dest=new_path, error=str(ex))
    return False
//  [python]
def move_files_on_change(calibre_path, new_authordir, new_titledir, localbook, db_filename, original_filepath, path):
    new_path = os.path.join(calibre_path, new_authordir, new_titledir)
    new_name = get_valid_filename(localbook.title, chars=96) + ' - ' + new_authordir
    try:
        if original_filepath:
            if not os.path.isdir(new_path):
                os.makedirs(new_path)
            shutil.move(os.path.normcase(original_filepath), os.path.normcase(os.path.join(new_path, db_filename)))
            log.debug("Moving title: %s to %s/%s", original_filepath, new_path, new_name)
        else:
            # Check new path is not valid path
            if not os.path.exists(new_path):
                # move original path to new path
                log.debug("Moving title: %s to %s", path, new_path)
                shutil.move(os.path.normcase(path), os.path.normcase(new_path))
            else: # path is valid copy only files to new location (merge)
                log.info("Moving title: %s into existing: %s", path, new_path)
                # Take all files and subfolder from old path (strange command)
                for dir_name, __, file_list in os.walk(path):
                    for file in file_list:
                        shutil.move(os.path.normcase(os.path.join(dir_name, file)),
                                        os.path.normcase(os.path.join(new_path + dir_name[len(path):], file)))
        # change location in database to new author/title path
        localbook.path = os.path.join(new_authordir, new_titledir).replace('\\','/')
    except OSError as ex:
        log.error("Rename title from: %s to %s: %s", path, new_path, ex)
        log.debug(ex, exc_info=True)
        return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                 src=path, dest=new_path, error=str(ex))
    return False
//  [python]
def save_cover_from_url(url, book_path):
    try:
        if cli.allow_localhost:
            img = requests.get(url, timeout=(10, 200), allow_redirects=False)  # ToDo: Error Handling
        elif use_advocate:
            img = advocate.get(url, timeout=(10, 200), allow_redirects=False)      # ToDo: Error Handling
        else:
            log.error("python modul advocate is not installed but is needed")
            return False, _("Python modul 'advocate' is not installed but is needed for cover downloads")
        img.raise_for_status()
        return save_cover(img, book_path)
    except (socket.gaierror,
            requests.exceptions.HTTPError,
            requests.exceptions.ConnectionError,
            requests.exceptions.Timeout) as ex:
        log.info(u'Cover Download Error %s', ex)
        return False, _("Error Downloading Cover")
    except MissingDelegateError as ex:
        log.info(u'File Format Error %s', ex)
        return False, _("Cover Format Error")
    except UnacceptableAddressException:
        log.error("Localhost was accessed for cover upload")
        return False, _("You are not allowed to access localhost for cover uploads")
//  [python]
def do_download_file(book, book_format, client, data, headers):
    if config.config_use_google_drive:
        # startTime = time.time()
        df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format)
        # log.debug('%s', time.time() - startTime)
        if df:
            return gd.do_gdrive_download(df, headers)
        else:
            abort(404)
    else:
        filename = os.path.join(config.config_calibre_dir, book.path)
        if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
            # ToDo: improve error handling
            log.error('File not found: %s', os.path.join(filename, data.name + "." + book_format))

        if client == "kobo" and book_format == "kepub":
            headers["Content-Disposition"] = headers["Content-Disposition"].replace(".kepub", ".kepub.epub")

        response = make_response(send_from_directory(filename, data.name + "." + book_format))
        # ToDo Check headers parameter
        for element in headers:
            response.headers[element[0]] = element[1]
        log.info('Downloading file: {}'.format(os.path.join(filename, data.name + "." + book_format)))
        return response
//  [python]
def do_download_file(book, book_format, client, data, headers):
    if config.config_use_google_drive:
        #startTime = time.time()
        df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format)
        #log.debug('%s', time.time() - startTime)
        if df:
            return gd.do_gdrive_download(df, headers)
        else:
            abort(404)
    else:
        filename = os.path.join(config.config_calibre_dir, book.path)
        if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
            # ToDo: improve error handling
            log.error('File not found: %s', os.path.join(filename, data.name + "." + book_format))

        if client == "kobo" and book_format == "kepub":
            headers["Content-Disposition"] = headers["Content-Disposition"].replace(".kepub", ".kepub.epub")

        response = make_response(send_from_directory(filename, data.name + "." + book_format))
        # ToDo Check headers parameter
        for element in headers:
            response.headers[element[0]] = element[1]
        log.info('Downloading file: {}'.format(os.path.join(filename, data.name + "." + book_format)))
        return response
//  [python]
def uniq(inpt):
    output = []
    inpt = [" ".join(inp.split()) for inp in inpt]
    for x in inpt:
        if x not in output:
            output.append(x)
    return output
//  [python]
def uniq(inpt):
    output = []
    inpt = [ " ".join(inp.split()) for inp in inpt]
    for x in inpt:
        if x not in output:
            output.append(x)
    return output
//  [python]
def update_dir_structure_gdrive(book_id, first_author, renamed_author):
    book = calibre_db.get_book(book_id)

    authordir = book.path.split('/')[0]
    titledir = book.path.split('/')[1]
    new_authordir = rename_all_authors(first_author, renamed_author, gdrive=True)
    new_titledir = get_valid_filename(book.title, chars=96) + u" (" + str(book_id) + u")"

    if titledir != new_titledir:
        g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir)
        if g_file:
            gd.moveGdriveFileRemote(g_file, new_titledir)
            book.path = book.path.split('/')[0] + u'/' + new_titledir
            gd.updateDatabaseOnEdit(g_file['id'], book.path)     # only child folder affected
        else:
            return _(u'File %(file)s not found on Google Drive', file=book.path)  # file not found

    if authordir != new_authordir and authordir not in renamed_author:
        g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), new_titledir)
        if g_file:
            gd.moveGdriveFolderRemote(g_file, new_authordir)
            book.path = new_authordir + u'/' + book.path.split('/')[1]
            gd.updateDatabaseOnEdit(g_file['id'], book.path)
        else:
            return _(u'File %(file)s not found on Google Drive', file=authordir)  # file not found

    # change location in database to new author/title path
    book.path = os.path.join(new_authordir, new_titledir).replace('\\', '/')
    return rename_files_on_change(first_author, renamed_author, book, gdrive=True)
//  [python]
def update_dir_structure_gdrive(book_id, first_author, renamed_author):
    book = calibre_db.get_book(book_id)

    authordir = book.path.split('/')[0]
    titledir = book.path.split('/')[1]
    new_authordir = rename_all_authors(first_author, renamed_author, gdrive=True)
    new_titledir = get_valid_filename(book.title, chars=96) + u" (" + str(book_id) + u")"

    if titledir != new_titledir:
        gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir)
        if gFile:
            gd.moveGdriveFileRemote(gFile, new_titledir)
            book.path = book.path.split('/')[0] + u'/' + new_titledir
            gd.updateDatabaseOnEdit(gFile['id'], book.path)     # only child folder affected
        else:
            return _(u'File %(file)s not found on Google Drive', file=book.path)  # file not found

    if authordir != new_authordir and authordir not in renamed_author:
        gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), new_titledir)
        if gFile:
            gd.moveGdriveFolderRemote(gFile, new_authordir)
            book.path = new_authordir + u'/' + book.path.split('/')[1]
            gd.updateDatabaseOnEdit(gFile['id'], book.path)
        else:
            return _(u'File %(file)s not found on Google Drive', file=authordir)  # file not found

    # change location in database to new author/title path
    book.path = os.path.join(new_authordir, new_titledir).replace('\\', '/')
    return rename_files_on_change(first_author, renamed_author, book, gdrive=True)
//  [python]
def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id):
    """Send email with attachments"""
    book = calibre_db.get_book(book_id)

    if convert == 1:
        # returns None if success, otherwise errormessage
        return convert_book_format(book_id, calibrepath, u'epub', book_format.lower(), user_id, kindle_mail)
    if convert == 2:
        # returns None if success, otherwise errormessage
        return convert_book_format(book_id, calibrepath, u'azw3', book_format.lower(), user_id, kindle_mail)

    for entry in iter(book.data):
        if entry.format.upper() == book_format.upper():
            converted_file_name = entry.name + '.' + book_format.lower()
            link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book_id), escape(book.title))
            email_text = _(u"%(book)s send to Kindle", book=link)
            WorkerThread.add(user_id, TaskEmail(_(u"Send to Kindle"), book.path, converted_file_name,
                             config.get_mail_settings(), kindle_mail,
                             email_text, _(u'This e-mail has been sent via Calibre-Web.')))
            return
    return _(u"The requested file could not be read. Maybe wrong permissions?")
//  [python]
def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id):
    """Send email with attachments"""
    book = calibre_db.get_book(book_id)

    if convert == 1:
        # returns None if success, otherwise errormessage
        return convert_book_format(book_id, calibrepath, u'epub', book_format.lower(), user_id, kindle_mail)
    if convert == 2:
        # returns None if success, otherwise errormessage
        return convert_book_format(book_id, calibrepath, u'azw3', book_format.lower(), user_id, kindle_mail)

    for entry in iter(book.data):
        if entry.format.upper() == book_format.upper():
            converted_file_name = entry.name + '.' + book_format.lower()
            link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book_id), escape(book.title))
            EmailText = _(u"%(book)s send to Kindle", book=link)
            WorkerThread.add(user_id, TaskEmail(_(u"Send to Kindle"), book.path, converted_file_name,
                             config.get_mail_settings(), kindle_mail,
                             EmailText, _(u'This e-mail has been sent via Calibre-Web.')))
            return
    return _(u"The requested file could not be read. Maybe wrong permissions?")
//  [python]
def testRunCommandInvalidInputKeyError(self, use_tfrt):
  self.parser = saved_model_cli.create_parser()
  base_path = test.test_src_dir_path(SAVED_MODEL_PATH)
  args = self.parser.parse_args([
      'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def',
      'regress_x2_to_y3', '--input_exprs', 'x2=[1,2,3]'
  ] + (['--use_tfrt'] if use_tfrt else []))
  with self.assertRaises(ValueError):
    saved_model_cli.run(args)
//  [python]
def testRunCommandInvalidInputKeyError(self, use_tfrt):
  self.parser = saved_model_cli.create_parser()
  base_path = test.test_src_dir_path(SAVED_MODEL_PATH)
  args = self.parser.parse_args([
      'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def',
      'regress_x2_to_y3', '--input_exprs', 'x2=np.ones((3,1))'
  ] + (['--use_tfrt'] if use_tfrt else []))
  with self.assertRaises(ValueError):
    saved_model_cli.run(args)
//  [python]
def _resolve_orders(orders):
    requester = get_user_or_app_from_context(info.context)
    if not requester.has_perm(OrderPermissions.MANAGE_ORDERS):
        # allow fetch requestor orders (except drafts)
        if root == info.context.user:
            orders = list(
                filter(lambda order: order.status != OrderStatus.DRAFT, orders)
            )
        else:
            raise PermissionDenied()

    return create_connection_slice(
        orders, info, kwargs, OrderCountableConnection
    )
//  [python]
def _resolve_orders(orders):
    requester = get_user_or_app_from_context(info.context)
    if not requester.has_perm(OrderPermissions.MANAGE_ORDERS):
        orders = list(
            filter(lambda order: order.status != OrderStatus.DRAFT, orders)
        )

    return create_connection_slice(
        orders, info, kwargs, OrderCountableConnection
    )
//  [python]
def upload_new_file_gdrive(book_id, first_author, renamed_author, title, title_dir, original_filepath, filename_ext):
    book = calibre_db.get_book(book_id)
    file_name = get_valid_filename(title, chars=42) + ' - ' + \
        get_valid_filename(first_author, chars=42) + filename_ext
    rename_all_authors(first_author, renamed_author, gdrive=True)
    gdrive_path = os.path.join(get_valid_filename(first_author, chars=96),
                               title_dir + " (" + str(book_id) + ")")
    book.path = gdrive_path.replace("\\", "/")
    gd.uploadFileToEbooksFolder(os.path.join(gdrive_path, file_name).replace("\\", "/"), original_filepath)
    return rename_files_on_change(first_author, renamed_author, localbook=book, gdrive=True)
//  [python]
def upload_new_file_gdrive(book_id, first_author, renamed_author, title, title_dir, original_filepath, filename_ext):
    error = False
    book = calibre_db.get_book(book_id)
    file_name = get_valid_filename(title, chars=42) + ' - ' + \
                get_valid_filename(first_author, chars=42) + \
                filename_ext
    rename_all_authors(first_author, renamed_author, gdrive=True)
    gdrive_path = os.path.join(get_valid_filename(first_author, chars=96),
                               title_dir + " (" + str(book_id) + ")")
    book.path = gdrive_path.replace("\\", "/")
    gd.uploadFileToEbooksFolder(os.path.join(gdrive_path, file_name).replace("\\", "/"), original_filepath)
    return rename_files_on_change(first_author, renamed_author, localbook=book, gdrive=True)
//  [python]
def resolve_orders(root: models.User, info, **kwargs):
    from ..order.types import OrderCountableConnection

    def _resolve_orders(orders):
        requester = get_user_or_app_from_context(info.context)
        if not requester.has_perm(OrderPermissions.MANAGE_ORDERS):
            # allow fetch requestor orders (except drafts)
            if root == info.context.user:
                orders = list(
                    filter(lambda order: order.status != OrderStatus.DRAFT, orders)
                )
            else:
                raise PermissionDenied()

        return create_connection_slice(
            orders, info, kwargs, OrderCountableConnection
        )

    return OrdersByUserLoader(info.context).load(root.id).then(_resolve_orders)
//  [python]
def resolve_orders(root: models.User, info, **kwargs):
    from ..order.types import OrderCountableConnection

    def _resolve_orders(orders):
        requester = get_user_or_app_from_context(info.context)
        if not requester.has_perm(OrderPermissions.MANAGE_ORDERS):
            orders = list(
                filter(lambda order: order.status != OrderStatus.DRAFT, orders)
            )

        return create_connection_slice(
            orders, info, kwargs, OrderCountableConnection
        )

    return OrdersByUserLoader(info.context).load(root.id).then(_resolve_orders)
//  [python]
def testRunCommandInvalidSignature(self, use_tfrt):
  self.parser = saved_model_cli.create_parser()
  base_path = test.test_src_dir_path(SAVED_MODEL_PATH)
  args = self.parser.parse_args([
      'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def',
      'INVALID_SIGNATURE', '--input_exprs', 'x2=[1,2,3]'
  ] + (['--use_tfrt'] if use_tfrt else []))
  with self.assertRaisesRegex(ValueError,
                              'Could not find signature "INVALID_SIGNATURE"'):
    saved_model_cli.run(args)
//  [python]
def testRunCommandInvalidSignature(self, use_tfrt):
  self.parser = saved_model_cli.create_parser()
  base_path = test.test_src_dir_path(SAVED_MODEL_PATH)
  args = self.parser.parse_args([
      'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def',
      'INVALID_SIGNATURE', '--input_exprs', 'x2=np.ones((3,1))'
  ] + (['--use_tfrt'] if use_tfrt else []))
  with self.assertRaisesRegex(ValueError,
                              'Could not find signature "INVALID_SIGNATURE"'):
    saved_model_cli.run(args)