Implement split library and books
Bugfix arrows in comic reader Fix kobo download link Updated requirement
This commit is contained in:
		
							parent
							
								
									fad6550ff1
								
							
						
					
					
						commit
						d68e57c4fc
					
				| 
						 | 
				
			
			@ -1702,7 +1702,7 @@ def _db_configuration_update_helper():
 | 
			
		|||
        return _db_configuration_result('{}'.format(ex), gdrive_error)
 | 
			
		||||
 | 
			
		||||
    if db_change or not db_valid or not config.db_configured \
 | 
			
		||||
        or config.config_calibre_dir != to_save["config_calibre_dir"]:
 | 
			
		||||
       or config.config_calibre_dir != to_save["config_calibre_dir"]:
 | 
			
		||||
        if not os.path.exists(metadata_db) or not to_save['config_calibre_dir']:
 | 
			
		||||
            return _db_configuration_result(_('DB Location is not Valid, Please Enter Correct Path'), gdrive_error)
 | 
			
		||||
        else:
 | 
			
		||||
| 
						 | 
				
			
			@ -1725,6 +1725,9 @@ def _db_configuration_update_helper():
 | 
			
		|||
        calibre_db.update_config(config)
 | 
			
		||||
        if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK):
 | 
			
		||||
            flash(_("DB is not Writeable"), category="warning")
 | 
			
		||||
    _config_string(to_save, "config_calibre_split_dir")
 | 
			
		||||
    config.config_calibre_split = to_save.get('config_calibre_split', 0) == "on"
 | 
			
		||||
    calibre_db.update_config(config)
 | 
			
		||||
    config.save()
 | 
			
		||||
    return _db_configuration_result(None, gdrive_error)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,8 @@ class _Settings(_Base):
 | 
			
		|||
 | 
			
		||||
    config_calibre_dir = Column(String)
 | 
			
		||||
    config_calibre_uuid = Column(String)
 | 
			
		||||
    config_calibre_split = Column(Boolean, default=False)
 | 
			
		||||
    config_calibre_split_dir = Column(String)
 | 
			
		||||
    config_port = Column(Integer, default=constants.DEFAULT_PORT)
 | 
			
		||||
    config_external_port = Column(Integer, default=constants.DEFAULT_PORT)
 | 
			
		||||
    config_certfile = Column(String)
 | 
			
		||||
| 
						 | 
				
			
			@ -389,6 +391,9 @@ class ConfigSQL(object):
 | 
			
		|||
        self.db_configured = False
 | 
			
		||||
        self.save()
 | 
			
		||||
 | 
			
		||||
    def get_book_path(self):
 | 
			
		||||
        return self.config_calibre_split_dir if self.config_calibre_split_dir else self.config_calibre_dir
 | 
			
		||||
 | 
			
		||||
    def store_calibre_uuid(self, calibre_db, Library_table):
 | 
			
		||||
        try:
 | 
			
		||||
            calibre_uuid = calibre_db.session.query(Library_table).one_or_none()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								cps/editbooks.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										22
									
								
								cps/editbooks.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -126,7 +126,7 @@ def edit_book(book_id):
 | 
			
		|||
            edited_books_id = book.id
 | 
			
		||||
            modify_date = True
 | 
			
		||||
            title_author_error = helper.update_dir_structure(edited_books_id,
 | 
			
		||||
                                                             config.config_calibre_dir,
 | 
			
		||||
                                                             config.get_book_path(),
 | 
			
		||||
                                                             input_authors[0],
 | 
			
		||||
                                                             renamed_author=renamed)
 | 
			
		||||
        if title_author_error:
 | 
			
		||||
| 
						 | 
				
			
			@ -271,7 +271,7 @@ def upload():
 | 
			
		|||
                                                  meta.extension.lower())
 | 
			
		||||
                else:
 | 
			
		||||
                    error = helper.update_dir_structure(book_id,
 | 
			
		||||
                                                        config.config_calibre_dir,
 | 
			
		||||
                                                        config.get_book_path(),
 | 
			
		||||
                                                        input_authors[0],
 | 
			
		||||
                                                        meta.file_path,
 | 
			
		||||
                                                        title_dir + meta.extension.lower(),
 | 
			
		||||
| 
						 | 
				
			
			@ -321,7 +321,7 @@ def convert_bookformat(book_id):
 | 
			
		|||
        return redirect(url_for('edit-book.show_edit_book', book_id=book_id))
 | 
			
		||||
 | 
			
		||||
    log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to)
 | 
			
		||||
    rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(),
 | 
			
		||||
    rtn = helper.convert_book_format(book_id, config.get_book_path(), book_format_from.upper(),
 | 
			
		||||
                                     book_format_to.upper(), current_user.name)
 | 
			
		||||
 | 
			
		||||
    if rtn is None:
 | 
			
		||||
| 
						 | 
				
			
			@ -391,7 +391,7 @@ def edit_list_book(param):
 | 
			
		|||
        elif param == 'title':
 | 
			
		||||
            sort_param = book.sort
 | 
			
		||||
            if handle_title_on_edit(book, vals.get('value', "")):
 | 
			
		||||
                rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir)
 | 
			
		||||
                rename_error = helper.update_dir_structure(book.id, config.get_book_path())
 | 
			
		||||
                if not rename_error:
 | 
			
		||||
                    ret = Response(json.dumps({'success': True, 'newValue':  book.title}),
 | 
			
		||||
                                   mimetype='application/json')
 | 
			
		||||
| 
						 | 
				
			
			@ -409,7 +409,7 @@ def edit_list_book(param):
 | 
			
		|||
                           mimetype='application/json')
 | 
			
		||||
        elif param == 'authors':
 | 
			
		||||
            input_authors, __, renamed = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == "true")
 | 
			
		||||
            rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir, input_authors[0],
 | 
			
		||||
            rename_error = helper.update_dir_structure(book.id, config.get_book_path(), input_authors[0],
 | 
			
		||||
                                                       renamed_author=renamed)
 | 
			
		||||
            if not rename_error:
 | 
			
		||||
                ret = Response(json.dumps({
 | 
			
		||||
| 
						 | 
				
			
			@ -513,10 +513,10 @@ def merge_list_book():
 | 
			
		|||
                    for element in from_book.data:
 | 
			
		||||
                        if element.format not in to_file:
 | 
			
		||||
                            # create new data entry with: book_id, book_format, uncompressed_size, name
 | 
			
		||||
                            filepath_new = os.path.normpath(os.path.join(config.config_calibre_dir,
 | 
			
		||||
                            filepath_new = os.path.normpath(os.path.join(config.get_book_path(),
 | 
			
		||||
                                                                         to_book.path,
 | 
			
		||||
                                                                         to_name + "." + element.format.lower()))
 | 
			
		||||
                            filepath_old = os.path.normpath(os.path.join(config.config_calibre_dir,
 | 
			
		||||
                            filepath_old = os.path.normpath(os.path.join(config.get_book_path(),
 | 
			
		||||
                                                                         from_book.path,
 | 
			
		||||
                                                                         element.name + "." + element.format.lower()))
 | 
			
		||||
                            copyfile(filepath_old, filepath_new)
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +556,7 @@ def table_xchange_author_title():
 | 
			
		|||
 | 
			
		||||
            if edited_books_id:
 | 
			
		||||
                # toDo: Handle error
 | 
			
		||||
                edit_error = helper.update_dir_structure(edited_books_id, config.config_calibre_dir, input_authors[0],
 | 
			
		||||
                edit_error = helper.update_dir_structure(edited_books_id, config.get_book_path(), input_authors[0],
 | 
			
		||||
                                                         renamed_author=renamed)
 | 
			
		||||
            if modify_date:
 | 
			
		||||
                book.last_modified = datetime.utcnow()
 | 
			
		||||
| 
						 | 
				
			
			@ -753,7 +753,7 @@ def move_coverfile(meta, db_book):
 | 
			
		|||
        cover_file = meta.cover
 | 
			
		||||
    else:
 | 
			
		||||
        cover_file = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg')
 | 
			
		||||
    new_cover_path = os.path.join(config.config_calibre_dir, db_book.path)
 | 
			
		||||
    new_cover_path = os.path.join(config.get_book_path(), db_book.path)
 | 
			
		||||
    try:
 | 
			
		||||
        os.makedirs(new_cover_path, exist_ok=True)
 | 
			
		||||
        copyfile(cover_file, os.path.join(new_cover_path, "cover.jpg"))
 | 
			
		||||
| 
						 | 
				
			
			@ -839,7 +839,7 @@ def delete_book_from_table(book_id, book_format, json_response):
 | 
			
		|||
        book = calibre_db.get_book(book_id)
 | 
			
		||||
        if book:
 | 
			
		||||
            try:
 | 
			
		||||
                result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
 | 
			
		||||
                result, error = helper.delete_book(book, config.get_book_path(), book_format=book_format.upper())
 | 
			
		||||
                if not result:
 | 
			
		||||
                    if json_response:
 | 
			
		||||
                        return json.dumps([{"location": url_for("edit-book.show_edit_book", book_id=book_id),
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,7 +1172,7 @@ def upload_single_file(file_request, book, book_id):
 | 
			
		|||
                return False
 | 
			
		||||
 | 
			
		||||
            file_name = book.path.rsplit('/', 1)[-1]
 | 
			
		||||
            filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
 | 
			
		||||
            filepath = os.path.normpath(os.path.join(config.get_book_path(), book.path))
 | 
			
		||||
            saved_filename = os.path.join(filepath, file_name + '.' + file_ext)
 | 
			
		||||
 | 
			
		||||
            # check if file path exists, otherwise create it, copy file to calibre path and delete temp file
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,8 @@ def get_epub_layout(book, book_data):
 | 
			
		|||
        'n': 'urn:oasis:names:tc:opendocument:xmlns:container',
 | 
			
		||||
        'pkg': 'http://www.idpf.org/2007/opf',
 | 
			
		||||
    }
 | 
			
		||||
    file_path = os.path.normpath(os.path.join(config.config_calibre_dir, book.path, book_data.name + "." + book_data.format.lower()))
 | 
			
		||||
    file_path = os.path.normpath(os.path.join(config.get_book_path(),
 | 
			
		||||
                                              book.path, book_data.name + "." + book_data.format.lower()))
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        epubZip = zipfile.ZipFile(file_path)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -781,7 +781,7 @@ def get_book_cover_internal(book, resolution=None):
 | 
			
		|||
 | 
			
		||||
        # Send the book cover from the Calibre directory
 | 
			
		||||
        else:
 | 
			
		||||
            cover_file_path = os.path.join(config.config_calibre_dir, book.path)
 | 
			
		||||
            cover_file_path = os.path.join(config.get_book_path(), book.path)
 | 
			
		||||
            if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")):
 | 
			
		||||
                return send_from_directory(cover_file_path, "cover.jpg")
 | 
			
		||||
            else:
 | 
			
		||||
| 
						 | 
				
			
			@ -934,7 +934,7 @@ def save_cover(img, book_path):
 | 
			
		|||
        else:
 | 
			
		||||
            return False, message
 | 
			
		||||
    else:
 | 
			
		||||
        return save_cover_from_filestorage(os.path.join(config.config_calibre_dir, book_path), "cover.jpg", img)
 | 
			
		||||
        return save_cover_from_filestorage(os.path.join(config.get_book_path(), book_path), "cover.jpg", img)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def do_download_file(book, book_format, client, data, headers):
 | 
			
		||||
| 
						 | 
				
			
			@ -947,7 +947,7 @@ def do_download_file(book, book_format, client, data, headers):
 | 
			
		|||
        else:
 | 
			
		||||
            abort(404)
 | 
			
		||||
    else:
 | 
			
		||||
        filename = os.path.join(config.config_calibre_dir, book.path)
 | 
			
		||||
        filename = os.path.join(config.get_book_path(), 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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -205,7 +205,7 @@ def HandleSyncRequest():
 | 
			
		|||
    for book in books:
 | 
			
		||||
        formats = [data.format for data in book.Books.data]
 | 
			
		||||
        if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats:
 | 
			
		||||
            helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name)
 | 
			
		||||
            helper.convert_book_format(book.Books.id, config.get_book_path(), 'EPUB', 'KEPUB', current_user.name)
 | 
			
		||||
 | 
			
		||||
        kobo_reading_state = get_or_create_reading_state(book.Books.id)
 | 
			
		||||
        entitlement = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,8 +179,9 @@ kthoom.ImageFile = function(file) {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
function updateDirectionButtons(){
 | 
			
		||||
    var left, right = 1;
 | 
			
		||||
    if (currentImage == 0 ) {
 | 
			
		||||
    var left = 1;
 | 
			
		||||
    var right = 1;
 | 
			
		||||
    if (currentImage <= 0 ) {
 | 
			
		||||
        if (settings.direction === 0) {
 | 
			
		||||
            left = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								cps/tasks/convert.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										6
									
								
								cps/tasks/convert.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -62,11 +62,11 @@ class TaskConvert(CalibreTask):
 | 
			
		|||
            df = gdriveutils.getFileFromEbooksFolder(cur_book.path,
 | 
			
		||||
                                                     data.name + "." + self.settings['old_book_format'].lower())
 | 
			
		||||
            if df:
 | 
			
		||||
                datafile = os.path.join(config.config_calibre_dir,
 | 
			
		||||
                datafile = os.path.join(config.get_book_path(),
 | 
			
		||||
                                        cur_book.path,
 | 
			
		||||
                                        data.name + "." + self.settings['old_book_format'].lower())
 | 
			
		||||
                if not os.path.exists(os.path.join(config.config_calibre_dir, cur_book.path)):
 | 
			
		||||
                    os.makedirs(os.path.join(config.config_calibre_dir, cur_book.path))
 | 
			
		||||
                if not os.path.exists(os.path.join(config.get_book_path(), cur_book.path)):
 | 
			
		||||
                    os.makedirs(os.path.join(config.get_book_path(), cur_book.path))
 | 
			
		||||
                df.GetContentFile(datafile)
 | 
			
		||||
                worker_db.session.close()
 | 
			
		||||
            else:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								cps/tasks/mail.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										2
									
								
								cps/tasks/mail.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -239,7 +239,7 @@ class TaskEmail(CalibreTask):
 | 
			
		|||
    @classmethod
 | 
			
		||||
    def _get_attachment(cls, book_path, filename):
 | 
			
		||||
        """Get file as MIMEBase message"""
 | 
			
		||||
        calibre_path = config.config_calibre_dir
 | 
			
		||||
        calibre_path = config.get_book_path()
 | 
			
		||||
        if config.config_use_google_drive:
 | 
			
		||||
            df = gdriveutils.getFileFromEbooksFolder(book_path, filename)
 | 
			
		||||
            if df:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ class TaskBackupMetadata(CalibreTask):
 | 
			
		|||
                                                 True)
 | 
			
		||||
        else:
 | 
			
		||||
            # ToDo: Handle book folder not found or not readable
 | 
			
		||||
            book_metadata_filepath = os.path.join(config.config_calibre_dir, book.path, 'metadata.opf')
 | 
			
		||||
            book_metadata_filepath = os.path.join(config.get_book_path(), book.path, 'metadata.opf')
 | 
			
		||||
            # prepare finalize everything and output
 | 
			
		||||
            doc = etree.ElementTree(package)
 | 
			
		||||
            try:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -209,7 +209,7 @@ class TaskGenerateCoverThumbnails(CalibreTask):
 | 
			
		|||
                    if stream is not None:
 | 
			
		||||
                        stream.close()
 | 
			
		||||
            else:
 | 
			
		||||
                book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg')
 | 
			
		||||
                book_cover_filepath = os.path.join(config.get_book_path(), book.path, 'cover.jpg')
 | 
			
		||||
                if not os.path.isfile(book_cover_filepath):
 | 
			
		||||
                    raise Exception('Book cover file not found')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask):
 | 
			
		|||
                        if stream is not None:
 | 
			
		||||
                            stream.close()
 | 
			
		||||
 | 
			
		||||
                book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg')
 | 
			
		||||
                book_cover_filepath = os.path.join(config.get_book_path(), book.path, 'cover.jpg')
 | 
			
		||||
                if not os.path.isfile(book_cover_filepath):
 | 
			
		||||
                    raise Exception('Book cover file not found')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,18 @@
 | 
			
		|||
          <button type="button" data-toggle="modal" id="calibre_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="form-group required">
 | 
			
		||||
        <input type="checkbox" id="config_calibre_split" name="config_calibre_split" data-control="split_settings" data-t ="{{ config.config_calibre_split_dir  }}" {% if config.config_calibre_split %}checked{% endif %} >
 | 
			
		||||
        <label for="config_calibre_split">{{_('Separate Book files from Library')}}</label>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div data-related="split_settings">
 | 
			
		||||
       <div class="form-group required input-group">
 | 
			
		||||
        <input type="text" class="form-control" id="config_calibre_split_dir" name="config_calibre_split_dir" value="{% if config.config_calibre_split_dir != None %}{{ config.config_calibre_split_dir }}{% endif %}" autocomplete="off">
 | 
			
		||||
        <span class="input-group-btn">
 | 
			
		||||
          <button type="button" data-toggle="modal" id="calibre_modal_split_path" data-link="config_calibre_split_dir" data-filefilter="" data-target="#fileModal" id="book_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    {% if feature_support['gdrive'] %}
 | 
			
		||||
      <div class="form-group required">
 | 
			
		||||
        <input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								cps/web.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										6
									
								
								cps/web.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -1192,7 +1192,7 @@ def serve_book(book_id, book_format, anyname):
 | 
			
		|||
        if book_format.upper() == 'TXT':
 | 
			
		||||
            log.info('Serving book: %s', data.name)
 | 
			
		||||
            try:
 | 
			
		||||
                rawdata = open(os.path.join(config.config_calibre_dir, book.path, data.name + "." + book_format),
 | 
			
		||||
                rawdata = open(os.path.join(config.get_book_path(), book.path, data.name + "." + book_format),
 | 
			
		||||
                               "rb").read()
 | 
			
		||||
                result = chardet.detect(rawdata)
 | 
			
		||||
                return make_response(
 | 
			
		||||
| 
						 | 
				
			
			@ -1202,7 +1202,7 @@ def serve_book(book_id, book_format, anyname):
 | 
			
		|||
                return "File Not Found"
 | 
			
		||||
        # enable byte range read of pdf
 | 
			
		||||
        response = make_response(
 | 
			
		||||
            send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format))
 | 
			
		||||
            send_from_directory(os.path.join(config.get_book_path(), book.path), data.name + "." + book_format))
 | 
			
		||||
        if not range_header:
 | 
			
		||||
            log.info('Serving book: %s', data.name)
 | 
			
		||||
            response.headers['Accept-Ranges'] = 'bytes'
 | 
			
		||||
| 
						 | 
				
			
			@ -1226,7 +1226,7 @@ def send_to_ereader(book_id, book_format, convert):
 | 
			
		|||
        response = [{'type': "danger", 'message': _("Please configure the SMTP mail settings first...")}]
 | 
			
		||||
        return Response(json.dumps(response), mimetype='application/json')
 | 
			
		||||
    elif current_user.kindle_mail:
 | 
			
		||||
        result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir,
 | 
			
		||||
        result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.get_book_path(),
 | 
			
		||||
                           current_user.name)
 | 
			
		||||
        if result is None:
 | 
			
		||||
            ub.update_download(book_id, int(current_user.id))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ iso-639>=0.4.5,<0.5.0
 | 
			
		|||
PyPDF>=3.0.0,<3.16.0
 | 
			
		||||
pytz>=2016.10
 | 
			
		||||
requests>=2.28.0,<2.32.0
 | 
			
		||||
SQLAlchemy>=1.3.0,<2.0.0
 | 
			
		||||
SQLAlchemy>=1.3.0,<2.1.0
 | 
			
		||||
tornado>=6.3,<6.4
 | 
			
		||||
Wand>=0.4.4,<0.7.0
 | 
			
		||||
unidecode>=0.04.19,<1.4.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ install_requires =
 | 
			
		|||
	PyPDF>=3.0.0,<3.16.0
 | 
			
		||||
	pytz>=2016.10
 | 
			
		||||
	requests>=2.28.0,<2.32.0
 | 
			
		||||
	SQLAlchemy>=1.3.0,<2.0.0
 | 
			
		||||
	SQLAlchemy>=1.3.0,<2.1.0
 | 
			
		||||
	tornado>=6.3,<6.4
 | 
			
		||||
	Wand>=0.4.4,<0.7.0
 | 
			
		||||
	unidecode>=0.04.19,<1.4.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user