diff --git a/.travis.yml b/.travis.yml index f6c2be7f3cde48ddd0aa8b22ce4a3de31de4f056..a407988ff1f463848318020b9108601ac11a0567 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ install: - travis_retry pip install -r requirements.txt script: - - python manage.py migrate database - python manage.py test #branches: diff --git a/opds_catalog/dl.py b/opds_catalog/dl.py index f1e44c187097a330b1fcfccc0a80edeafcf2deda..0728f9e1e564616494e6bb7c766d841b0524eb97 100644 --- a/opds_catalog/dl.py +++ b/opds_catalog/dl.py @@ -11,15 +11,16 @@ from django.http import HttpResponse, Http404 from opds_catalog.models import Book, bookshelf from opds_catalog import settings, utils, opdsdb, fb2parse import opds_catalog.zipf as zipfile +from constance import config def Download(request, book_id, zip_flag): """ Загрузка файла книги """ book = Book.objects.get(id=book_id) - if settings.AUTH and request.user.is_authenticated(): + if config.SOPDS_AUTH and request.user.is_authenticated(): bookshelf.objects.get_or_create(user=request.user, book=book) - full_path=os.path.join(settings.ROOT_LIB,book.path) + full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path) if book.cat_type==opdsdb.CAT_INP: # Убираем из пути INPX файл @@ -27,7 +28,7 @@ def Download(request, book_id, zip_flag): path, inpx_file = os.path.split(inpx_path) full_path = os.path.join(path,zip_name) - if settings.TITLE_AS_FILENAME: + if config.SOPDS_TITLE_AS_FILENAME: transname=utils.translit(book.title+'.'+book.format) else: transname=utils.translit(book.filename) @@ -98,7 +99,7 @@ def Cover(request, book_id): book = Book.objects.get(id=book_id) response = HttpResponse() c0=0 - full_path=os.path.join(settings.ROOT_LIB,book.path) + full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path) if book.cat_type==opdsdb.CAT_INP: # Убираем из пути INPX файл inpx_path, zip_name = os.path.split(full_path) @@ -132,9 +133,9 @@ def Cover(request, book_id): c0=0 if c0==0: - if os.path.exists(settings.NOCOVER_PATH): + if os.path.exists(config.SOPDS_NOCOVER_PATH): response["Content-Type"]='image/jpeg' - f=open(settings.NOCOVER_PATH,"rb") + f=open(config.SOPDS_NOCOVER_PATH,"rb") response.write(f.read()) f.close() else: @@ -149,17 +150,17 @@ def ConvertFB2(request, book_id, convert_type): if book.format!='fb2': raise Http404 - if settings.AUTH and request.user.is_authenticated(): + if config.SOPDS_AUTH and request.user.is_authenticated(): bookshelf.objects.get_or_create(user=request.user, book=book) - full_path=os.path.join(settings.ROOT_LIB,book.path) + full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path) if book.cat_type==opdsdb.CAT_INP: # Убираем из пути INPX файл inpx_path, zip_name = os.path.split(full_path) path, inpx_file = os.path.split(inpx_path) full_path = os.path.join(path,zip_name) - if settings.TITLE_AS_FILENAME: + if config.SOPDS_TITLE_AS_FILENAME: transname=utils.translit(book.title+'.'+book.format) else: transname=utils.translit(book.filename) @@ -170,10 +171,10 @@ def ConvertFB2(request, book_id, convert_type): dlfilename="%s.%s"%(n,convert_type) if convert_type=='epub': - converter_path=settings.FB2TOEPUB + converter_path=config.SOPDS_FB2TOEPUB content_type='application/epub+zip' elif convert_type=='mobi': - converter_path=settings.FB2TOMOBI + converter_path=config.SOPDS_FB2TOMOBI content_type='application/x-mobipocket-ebook' else: content_type='application/octet-stream' @@ -187,11 +188,11 @@ def ConvertFB2(request, book_id, convert_type): except FileNotFoundError: raise Http404 z = zipfile.ZipFile(fz, 'r', allowZip64=True) - z.extract(book.filename,settings.TEMP_DIR) - tmp_fb2_path=os.path.join(settings.TEMP_DIR,book.filename) + z.extract(book.filename,config.SOPDS_TEMP_DIR) + tmp_fb2_path=os.path.join(config.SOPDS_TEMP_DIR,book.filename) file_path=tmp_fb2_path - tmp_conv_path=os.path.join(settings.TEMP_DIR,dlfilename) + tmp_conv_path=os.path.join(config.SOPDS_TEMP_DIR,dlfilename) popen_args = ("\"%s\" \"%s\" \"%s\""%(converter_path,file_path,tmp_conv_path)) proc = subprocess.Popen(popen_args, shell=True, stdout=subprocess.PIPE) #proc = subprocess.Popen((converter_path.encode('utf8'),file_path.encode('utf8'),tmp_conv_path.encode('utf8')), shell=True, stdout=subprocess.PIPE) diff --git a/opds_catalog/feeds.py b/opds_catalog/feeds.py index e379ae0d206c1c52d4b97fc3c35ca4fabe2d70aa..47cdf6ec2b841ed511160464f0b41edbcc0fb1e9 100644 --- a/opds_catalog/feeds.py +++ b/opds_catalog/feeds.py @@ -15,11 +15,13 @@ from opds_catalog import settings from opds_catalog.opds_middleware import BasicAuthMiddleware from opds_catalog.opds_paginator import Paginator as OPDS_Paginator +from constance import config + class AuthFeed(Feed): request = None def __call__(self,request,*args,**kwargs): self.request = request - if settings.AUTH: + if config.SOPDS_AUTH: if request.user.is_authenticated(): return super().__call__(request,*args,**kwargs) @@ -159,16 +161,16 @@ class MainFeed(AuthFeed): mainitems = [ {"id":1, "title":_("By catalogs"), "link":"opds_catalog:catalogs", "descr": _("Catalogs: %(catalogs)s, books: %(books)s."),"counters":{"catalogs":Counter.objects.get_counter(models.counter_allcatalogs),"books":Counter.objects.get_counter(models.counter_allbooks)}}, - {"id":2, "title":_("By authors"), "link":("opds_catalog:lang_authors" if settings.ALPHABET_MENU else "opds_catalog:nolang_authors"), + {"id":2, "title":_("By authors"), "link":("opds_catalog:lang_authors" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_authors"), "descr": _("Authors: %(authors)s."),"counters":{"authors":Counter.objects.get_counter(models.counter_allauthors)}}, - {"id":3, "title":_("By titles"), "link":("opds_catalog:lang_books" if settings.ALPHABET_MENU else "opds_catalog:nolang_books"), + {"id":3, "title":_("By titles"), "link":("opds_catalog:lang_books" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_books"), "descr": _("Books: %(books)s."),"counters":{"books":Counter.objects.get_counter(models.counter_allbooks)}}, {"id":4, "title":_("By genres"), "link":"opds_catalog:genres", "descr": _("Genres: %(genres)s."),"counters":{"genres":Counter.objects.get_counter(models.counter_allgenres)}}, - {"id":5, "title":_("By series"), "link":("opds_catalog:lang_series" if settings.ALPHABET_MENU else "opds_catalog:nolang_series"), + {"id":5, "title":_("By series"), "link":("opds_catalog:lang_series" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_series"), "descr": _("Series: %(series)s."),"counters":{"series":Counter.objects.get_counter(models.counter_allseries)}}, ] - if settings.AUTH and self.request.user.is_authenticated(): + if config.SOPDS_AUTH and self.request.user.is_authenticated(): mainitems += [ {"id":6, "title":_("%(username)s Book shelf")%({"username":self.request.user.username}), "link":"opds_catalog:bookshelf", "descr":_("%(username)s books readed: %(bookshelf)s."),"counters":{"bookshelf":bookshelf.objects.filter(user=self.request.user).count(),"username":self.request.user.username}}, @@ -223,7 +225,7 @@ class CatalogsFeed(AuthFeed): books_count = books_list.count() # Получаем результирующий список - op = OPDS_Paginator(catalogs_count, books_count, page_num, settings.MAXITEMS) + op = OPDS_Paginator(catalogs_count, books_count, page_num, config.SOPDS_MAXITEMS) items = [] for row in catalogs_list[op.d1_first_pos:op.d1_last_pos+1]: @@ -372,7 +374,7 @@ class SearchBooksFeed(AuthFeed): subtitle = settings.SUBTITLE def title(self, obj): - return "%s | %s (%s)"%(settings.TITLE,_("Books found"),_("doubles hide") if settings.DOUBLES_HIDE else _("doubles show")) + return "%s | %s (%s)"%(settings.TITLE,_("Books found"),_("doubles hide") if config.SOPDS_DOUBLES_HIDE else _("doubles show")) def get_object(self, request, searchtype="m", searchterms=None, searchterms0=None, page=1): if not isinstance(page, int): @@ -423,7 +425,7 @@ class SearchBooksFeed(AuthFeed): books = Book.objects.filter(genres=genre_id).order_by('search_title','-docdate') # Поиск книг на книжной полке elif searchtype == 'u': - if settings.AUTH: + if config.SOPDS_AUTH: books = Book.objects.filter(bookshelf__user=request.user).order_by('-bookshelf__readtime') else: books=Book.objects.filter(id=0) @@ -439,7 +441,7 @@ class SearchBooksFeed(AuthFeed): # Фильтруем дубликаты books_count = books.count() - op = OPDS_Paginator(books_count, 0, page_num,settings.MAXITEMS) + op = OPDS_Paginator(books_count, 0, page_num,config.SOPDS_MAXITEMS) items = [] prev_title = '' @@ -447,7 +449,7 @@ class SearchBooksFeed(AuthFeed): # Начаинам анализ с последнего элемента на предидущей странице, чторбы он "вытянул" с этой страницы # свои дубликаты если они есть - summary_DOUBLES_HIDE = settings.DOUBLES_HIDE and (searchtype != 'd') + summary_DOUBLES_HIDE = config.SOPDS_DOUBLES_HIDE and (searchtype != 'd') start = op.d1_first_pos if ((op.d1_first_pos==0) or (not summary_DOUBLES_HIDE)) else op.d1_first_pos-1 finish = op.d1_last_pos @@ -534,9 +536,9 @@ class SearchBooksFeed(AuthFeed): opdsEnclosure(reverse("opds_catalog:download", kwargs={"book_id":item['id'],"zip_flag":1}),"application/%s+zip"%item['format'], "http://opds-spec.org/acquisition/open-access"), opdsEnclosure(reverse("opds_catalog:cover", kwargs={"book_id":item['id']}),"image/jpeg", "http://opds-spec.org/image"), ] - if (settings.FB2TOEPUB!="") and (item['format']=='fb2'): + if (config.SOPDS_FB2TOEPUB!="") and (item['format']=='fb2'): enclosure += [opdsEnclosure(reverse("opds_catalog:convert", kwargs={"book_id":item['id'],"convert_type":"epub"}),"application/epub+zip","http://opds-spec.org/acquisition/open-access")] - if (settings.FB2TOMOBI!="") and (item['format']=='fb2'): + if (config.SOPDS_FB2TOMOBI!="") and (item['format']=='fb2'): enclosure += [opdsEnclosure(reverse("opds_catalog:convert", kwargs={"book_id":item['id'],"convert_type":"mobi"}),"application/mobi","http://opds-spec.org/acquisition/open-access")] return enclosure @@ -634,7 +636,7 @@ class SearchAuthorsFeed(AuthFeed): # Создаем результирующее множество authors_count = authors.count() - op = OPDS_Paginator(authors_count, 0, page_num, settings.MAXITEMS) + op = OPDS_Paginator(authors_count, 0, page_num, config.SOPDS_MAXITEMS) items = [] for row in authors[op.d1_first_pos:op.d1_last_pos+1]: @@ -712,7 +714,7 @@ class SearchSeriesFeed(AuthFeed): # Создаем результирующее множество series_count = series.count() - op = OPDS_Paginator(series_count, 0, page_num, settings.MAXITEMS) + op = OPDS_Paginator(series_count, 0, page_num, config.SOPDS_MAXITEMS) items = [] for row in series[op.d1_first_pos:op.d1_last_pos+1]: @@ -860,7 +862,7 @@ class BooksFeed(AuthFeed): def item_link(self, item): title_full = len(item.id)<item.l - if item.cnt>=settings.SPLITITEMS and not title_full: + if item.cnt>=config.SOPDS_SPLITITEMS and not title_full: return reverse("opds_catalog:chars_books", kwargs={"lang_code":self.lang_code,"chars":item.id}) else: return reverse("opds_catalog:searchbooks", \ @@ -918,7 +920,7 @@ class AuthorsFeed(AuthFeed): def item_link(self, item): last_name_full = len(item.id)<item.l - if (item.cnt>=settings.SPLITITEMS) and not last_name_full: + if (item.cnt>=config.SOPDS_SPLITITEMS) and not last_name_full: return reverse("opds_catalog:chars_authors", kwargs={"lang_code":self.lang_code,"chars":item.id}) else: return reverse("opds_catalog:searchauthors", \ @@ -976,7 +978,7 @@ class SeriesFeed(AuthFeed): def item_link(self, item): series_full = len(item.id)<item.l - if item.cnt>=settings.SPLITITEMS and not series_full: + if item.cnt>=config.SOPDS_SPLITITEMS and not series_full: return reverse("opds_catalog:chars_series", kwargs={"lang_code":self.lang_code,"chars":item.id}) else: return reverse("opds_catalog:searchseries", \ diff --git a/opds_catalog/inpx_parser.py b/opds_catalog/inpx_parser.py index 525c25e48c77f038eaecf77b85290a7fd0db8c58..b781962679e518cc130bd7d4431ad3f700b053e1 100644 --- a/opds_catalog/inpx_parser.py +++ b/opds_catalog/inpx_parser.py @@ -7,7 +7,8 @@ Created on 14 нояб. 2016 г. # -*- coding: utf-8 -*- import os import zipfile -from opds_catalog import settings +#from opds_catalog import settings +from constance import config sAuthor = 'AUTHOR' sGenre = 'GENRE' @@ -32,8 +33,8 @@ class Inpx: self.inpx_itemseparator = ':' self.append_callback = append_callback self.inpskip_callback = inpskip_callback - self.TEST_ZIP = settings.INPX_TEST_ZIP - self.TEST_FILES = settings.INPX_TEST_FILES + self.TEST_ZIP = config.SOPDS_INPX_TEST_ZIP + self.TEST_FILES = config.SOPDS_INPX_TEST_FILES self.error = 0 def parse(self): diff --git a/opds_catalog/management/commands/sopds_scanner.py b/opds_catalog/management/commands/sopds_scanner.py index 317ad33fc958fb3235d05e078753ad4ba2076e93..5ffba26a6e7e771d1db7bd3b3ea5b6dda4a0bb5a 100644 --- a/opds_catalog/management/commands/sopds_scanner.py +++ b/opds_catalog/management/commands/sopds_scanner.py @@ -14,8 +14,7 @@ from opds_catalog.models import Counter from opds_catalog.sopdscan import opdsScanner #from opds_catalog.settings import SCANNER_LOG, SCAN_SHED_DAY, SCAN_SHED_DOW, SCAN_SHED_HOUR, SCAN_SHED_MIN, LOGLEVEL, SCANNER_PID from opds_catalog import settings - - +from constance import config class Command(BaseCommand): help = 'Scan Books Collection.' @@ -26,7 +25,7 @@ class Command(BaseCommand): parser.add_argument('--daemon',action='store_true', dest='daemonize', default=False, help='Daemonize server') def handle(self, *args, **options): - self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SCANNER_PID) + self.pidfile = os.path.join(main_settings.BASE_DIR, config.SOPDS_SCANNER_PID) action = options['command'] self.logger = logging.getLogger('') self.logger.setLevel(logging.DEBUG) @@ -34,7 +33,7 @@ class Command(BaseCommand): if settings.LOGLEVEL!=logging.NOTSET: # Создаем обработчик для записи логов в файл - fh = logging.FileHandler(settings.SCANNER_LOG) + fh = logging.FileHandler(config.SOPDS_SCANNER_LOG) fh.setLevel(settings.LOGLEVEL) fh.setFormatter(formatter) self.logger.addHandler(fh) @@ -78,26 +77,28 @@ class Command(BaseCommand): Counter.objects.update_known_counters() def update_shedule(self): - self.SCAN_SHED_DAY = settings.SCAN_SHED_DAY - self.SCAN_SHED_DOW = settings.SCAN_SHED_DOW - self.SCAN_SHED_HOUR = settings.SCAN_SHED_HOUR - self.SCAN_SHED_MIN = settings.SCAN_SHED_MIN + self.SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY + self.SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW + self.SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR + self.SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN self.stdout.write('Reconfigure scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(self.SCAN_SHED_MIN,self.SCAN_SHED_HOUR,self.SCAN_SHED_DOW,self.SCAN_SHED_DAY)) self.sched.reschedule_job('scan', trigger='cron', day=self.SCAN_SHED_DAY, day_of_week=self.SCAN_SHED_DOW, hour=self.SCAN_SHED_HOUR, minute=self.SCAN_SHED_MIN) def check_settings(self): - settings.constance_update_shedules() - if self.SCAN_SHED_MIN==settings.SCAN_SHED_MIN and self.SCAN_SHED_HOUR==settings.SCAN_SHED_HOUR and self.SCAN_SHED_DOW==settings.SCAN_SHED_DOW and self.SCAN_SHED_DAY==settings.SCAN_SHED_DAY: - return settings.constance_update_all() + if self.SCAN_SHED_MIN==config.SOPDS_SCAN_SHED_MIN and \ + self.SCAN_SHED_HOUR==config.SOPDS_SCAN_SHED_HOUR and \ + self.SCAN_SHED_DOW==config.SOPDS_SCAN_SHED_DOW and \ + self.SCAN_SHED_DAY==config.SOPDS_SCAN_SHED_DAY: + return self.update_shedule() def start(self): writepid(self.pidfile) - self.SCAN_SHED_DAY = settings.SCAN_SHED_DAY - self.SCAN_SHED_DOW = settings.SCAN_SHED_DOW - self.SCAN_SHED_HOUR = settings.SCAN_SHED_HOUR - self.SCAN_SHED_MIN = settings.SCAN_SHED_MIN + self.SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY + self.SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW + self.SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR + self.SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN self.stdout.write('Startup scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(self.SCAN_SHED_MIN,self.SCAN_SHED_HOUR,self.SCAN_SHED_DOW,self.SCAN_SHED_DAY)) self.sched = BlockingScheduler() self.sched.add_job(self.scan, 'cron', day=self.SCAN_SHED_DAY, day_of_week=self.SCAN_SHED_DOW, hour=self.SCAN_SHED_HOUR, minute=self.SCAN_SHED_MIN, id='scan') @@ -141,7 +142,7 @@ def daemonize(): os.umask(0) std_in = open("/dev/null", 'r') - std_out = open(settings.SCANNER_LOG, 'a+') + std_out = open(config.SOPDS_SCANNER_LOG, 'a+') os.dup2(std_in.fileno(), sys.stdin.fileno()) os.dup2(std_out.fileno(), sys.stdout.fileno()) os.dup2(std_out.fileno(), sys.stderr.fileno()) diff --git a/opds_catalog/management/commands/sopds_server.py b/opds_catalog/management/commands/sopds_server.py index 68030715c19db962b1aaa4a5ef807749ced1b061..8af848560062b0c75860c01c5921656ab2436271 100644 --- a/opds_catalog/management/commands/sopds_server.py +++ b/opds_catalog/management/commands/sopds_server.py @@ -7,7 +7,8 @@ from django.core.management.base import BaseCommand from django.core.management import call_command #from opds_catalog.settings import SERVER_LOG, SERVER_PID -from opds_catalog import settings +#from opds_catalog import settings +from constance import config class Command(BaseCommand): help = 'HTTP/OPDS built-in server' @@ -20,7 +21,7 @@ class Command(BaseCommand): def handle(self, *args, **options): - self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SERVER_PID) + self.pidfile = os.path.join(main_settings.BASE_DIR, config.SOPDS_SERVER_PID) action = options['command'] self.addr = options['host'] self.port = int(options['port']) @@ -76,7 +77,7 @@ def daemonize(): os.umask(0) std_in = open("/dev/null", 'r') - std_out = open(settings.SERVER_LOG, 'a+') + std_out = open(config.SOPDS_SERVER_LOG, 'a+') os.dup2(std_in.fileno(), sys.stdin.fileno()) os.dup2(std_out.fileno(), sys.stdout.fileno()) os.dup2(std_out.fileno(), sys.stderr.fileno()) diff --git a/opds_catalog/opds_middleware.py b/opds_catalog/opds_middleware.py index 07f07c08f93019fa6d0e9cfaad817294011132c0..490bbd261e2bb7e1b4af99a2bea8abc5ce62c806 100644 --- a/opds_catalog/opds_middleware.py +++ b/opds_catalog/opds_middleware.py @@ -5,8 +5,8 @@ from django.contrib import auth from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import resolve -from opds_catalog import settings - +#from opds_catalog import settings +from constance import config class BasicAuthMiddleware(object): header = "HTTP_AUTHORIZATION" @@ -19,7 +19,7 @@ class BasicAuthMiddleware(object): return response def process_request(self,request): - if not settings.AUTH: + if not config.SOPDS_AUTH: return # AuthenticationMiddleware is required so that request.user exists. diff --git a/opds_catalog/settings.py b/opds_catalog/settings.py index 3c1077e355e53132496c78395f6f2f6dc8f4accb..9c10cacf5eb9c093c196ef9f1b15f247198389aa 100644 --- a/opds_catalog/settings.py +++ b/opds_catalog/settings.py @@ -6,102 +6,6 @@ from constance import config loglevels={'debug':logging.DEBUG,'info':logging.INFO,'warning':logging.WARNING,'error':logging.ERROR,'critical':logging.CRITICAL,'none':logging.NOTSET} VERSION = "0.40" - -# ROOT_LIB содержит путь к каталогу в котором расположена ваша коллекция книг -ROOT_LIB = config.SOPDS_ROOT_LIB - -# Списк форматов книг, которые будут включаться в каталог -BOOK_EXTENSIONS = config.SOPDS_BOOK_EXTENSIONS.split() - -# Скрывает, найденные дубликаты в выдачах книг -DOUBLES_HIDE = config.SOPDS_DOUBLES_HIDE - -# Извлекать метаинформацию из книг fb2 -FB2PARSE = config.SOPDS_FB2PARSE - -# cover_show - способ показа обложек: -# False - не показывать, -# True - извлекать обложки на лету и показывать -COVER_SHOW = config.SOPDS_COVER_SHOW - -# ZIPSCAN = True - Приводит к сканированию файлов архива -ZIPSCAN = config.SOPDS_ZIPSCAN - -# Указываем какая кодировка для названий файлов используется в ZIP-архивах -# доступные кодировки: cp437, cp866, cp1251, utf-8 -# по умолчанию применяется кодировка cp437 -# Поскольку в самом ZIP архиве сведения о кодировке, в которой находятся имена файлов - отсутствуют -# то автоматически определить правильную кодировку для имен файлов не представляется возможным -# поэтому для того чтобы кириллические имена файлов не ваыглядели как крякозябры следует применять кодировку cp866 -# по умолчанию также используется значение zip_codepage = cp866 -ZIPCODEPAGE = config.SOPDS_ZIPCODEPAGE - -# Если INPX_ENABLE = True, то при обнаружении INPX файла в каталоге, сканер не сканирует его содержимое вместе с подгаталогами, а загружает -# данные из найденного INPX файла. Сканер считает что сами архивыс книгами расположены в этом же каталоге. -# Т.е. INPX-файл должен находится именно в папке с архивами книг -INPX_ENABLE = config.SOPDS_INPX_ENABLE - -# Если INPX_SKIP_UNCHANGED = True, то сканер пропускает повторное сканирование, если размер INPX не изменялся -INPX_SKIP_UNCHANGED = config.SOPDS_INPX_SKIP_UNCHANGED - -# Если INPX_TEST_ZIP = True, то сканер пытается найти описанный в INPX архив. Если какой-то архив не обнаруживается, -# то сканер не будет добавлять вязанные с ним данные из INPX в базу данных -# соответсвенно, если INPX_TEST_ZIP = False, то никаких проверок сканер не производит, а просто добавляет данные из INPX в БД -# это гораздо быстрее -INPX_TEST_ZIP = config.SOPDS_INPX_TEST_ZIP - -# Если INPX_TEST_FILES = True, то сканер пытается найти описанный в INPX конкретный файл с книгой (уже внутри архивов). Если какой-то файл не обнаруживается, -# то сканер не будет добавлять эту книгу в базу данных -# соответсвенно, если INPX_TEST_FILES = False, то никаких проверок сканер не производит, а просто добавляет книгу из INPX в БД -# это гораздо быстрее -INPX_TEST_FILES = config.SOPDS_INPX_TEST_FILES - -# Установка DELETE_LOGICAL=True приведет к тому, что при обнаружении сканером, что книга удалена, запись в БД об этой книге будет удалена логически (avail=0) -# Если DELETE_LOGICAL=False, то произойдет физическое удаление таких записей из базы данных -# пока работает только DELETE_LOGICAL = False -DELETE_LOGICAL = config.SOPDS_DELETE_LOGICAL - -SPLITITEMS = config.SOPDS_SPLITITEMS - -# Количество выдаваемых результатов на одну страницу -MAXITEMS = config.SOPDS_MAXITEMS - -# FB2TOEPUB и FB2TOMOBI задают пути к програмам - конвертерам из FB2 в EPUB и MOBI -FB2TOEPUB = config.SOPDS_FB2TOEPUB -FB2TOMOBI = config.SOPDS_FB2TOMOBI - -# TEMP_DIR задает путь к временному каталогу, который используется для копирования оригинала и результата конвертации -TEMP_DIR = config.SOPDS_TEMP_DIR - -# При скачивании вместо оригинального имени файла книги выдает транслитерацию названия книги -TITLE_AS_FILENAME = config.SOPDS_TITLE_AS_FILENAME - -# Включение дополнительного меню выбора алфавита -ALPHABET_MENU = config.SOPDS_ALPHABET_MENU - -# Обложка, которая будет демонстрироваться для книг без обложек -NOCOVER_PATH = config.SOPDS_NOCOVER_PATH - -# Включение BASIC - авторизации -AUTH = config.SOPDS_AUTH - -# параметры SERVER_LOG и SCANNER_LOG задают размещение LOG файлов этих процессов -SERVER_LOG = config.SOPDS_SERVER_LOG -SCANNER_LOG = config.SOPDS_SCANNER_LOG - -# параметры SERVER_PID и SCANNER_PID задают размещение PID файлов этих процессов при демонизации -SERVER_PID = config.SOPDS_SERVER_PID -SCANNER_PID = config.SOPDS_SCANNER_PID - -# SCAN_SHED устанавливают значения шедулера, для периодического сканирования коллекции книг -# при помощи manage.py sopds_scanner ... -# Возможные значения можно найти на следующей странице; -# https://apscheduler.readthedocs.io/en/latest/modules/triggers/cron.html#module-apscheduler.triggers.cron -SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN -SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR -SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY -SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW - TITLE = getattr(settings, "SOPDS_TITLE", "SimpleOPDS") SUBTITLE = getattr(settings, "SOPDS_SUBTITLE", "SimpleOPDS Catalog by www.sopds.ru. Version %s."%VERSION) ICON = getattr(settings, "SOPDS_ICON", "/static/images/favicon.ico") @@ -112,31 +16,13 @@ if loglevel.lower() in loglevels: else: LOGLEVEL=logging.NOTSET -# Отработка изменения конфигурации -import sys -from constance.signals import config_updated -from django.dispatch import receiver - -@receiver(config_updated) -def constance_updated(sender, updated_key, new_value, **kwargs): - if updated_key == 'SOPDS_BOOK_EXTENSIONS': - value = new_value.split() - else: - value = new_value - key=updated_key.replace('SOPDS_','') - setattr(sys.modules[__name__], key, value) - -def constance_update_shedules(): - setattr(sys.modules[__name__], 'SCAN_SHED_MIN', config.SOPDS_SCAN_SHED_MIN) - setattr(sys.modules[__name__], 'SCAN_SHED_HOUR', config.SOPDS_SCAN_SHED_HOUR) - setattr(sys.modules[__name__], 'SCAN_SHED_DAY', config.SOPDS_SCAN_SHED_DAY) - setattr(sys.modules[__name__], 'SCAN_SHED_DOW', config.SOPDS_SCAN_SHED_DOW) - + def constance_update_all(): pass # Переопределяем некоторые функции для SQLite, которые работают неправлено from django.db.backends.signals import connection_created +from django.dispatch import receiver def sopds_upper(s): return s.upper() diff --git a/opds_catalog/sopdscan.py b/opds_catalog/sopdscan.py index e4816db2b9d22a3a7c805fcb9a1e4d241a16532b..e89204cdbe73fdbc60cd4cfe339c1e80d17d00a1 100644 --- a/opds_catalog/sopdscan.py +++ b/opds_catalog/sopdscan.py @@ -8,10 +8,13 @@ import re from django.db import transaction -from opds_catalog import fb2parse, settings, opdsdb +from opds_catalog import fb2parse, opdsdb from opds_catalog import inpx_parser +#from opds_catalog import settings import opds_catalog.zipf as zipfile +from constance import config + class opdsScanner: def __init__(self, logger=None): self.fb2parser=None @@ -44,17 +47,17 @@ class opdsScanner: def log_options(self): self.logger.info(' ***** Starting sopds-scan...') self.logger.debug('OPTIONS SET') - if settings.ROOT_LIB!=None: self.logger.debug('root_lib = '+settings.ROOT_LIB) - if settings.FB2TOEPUB!=None: self.logger.debug('fb2toepub = '+settings.FB2TOEPUB) - if settings.FB2TOMOBI!=None: self.logger.debug('fb2tomobi = '+settings.FB2TOMOBI) - if settings.TEMP_DIR!=None: self.logger.debug('temp_dir = '+settings.TEMP_DIR) + if config.SOPDS_ROOT_LIB!=None: self.logger.debug('root_lib = '+config.SOPDS_ROOT_LIB) + if config.SOPDS_FB2TOEPUB!=None: self.logger.debug('fb2toepub = '+config.SOPDS_FB2TOEPUB) + if config.SOPDS_FB2TOMOBI!=None: self.logger.debug('fb2tomobi = '+config.SOPDS_FB2TOMOBI) + if config.SOPDS_TEMP_DIR!=None: self.logger.debug('temp_dir = '+config.SOPDS_TEMP_DIR) def log_stats(self): self.t2=datetime.timedelta(seconds=time.time()) self.logger.info('Books added : '+str(self.books_added)) self.logger.info('Books skipped : '+str(self.books_skipped)) self.logger.info('Bad books : '+str(self.bad_books)) - if settings.DELETE_LOGICAL: + if config.SOPDS_DELETE_LOGICAL: self.logger.info('Books deleted : '+str(self.books_deleted)) else: self.logger.info('Books DB entries deleted : '+str(self.books_deleted)) @@ -78,9 +81,9 @@ class opdsScanner: opdsdb.avail_check_prepare() - for full_path, dirs, files in os.walk(settings.ROOT_LIB, followlinks=True): + for full_path, dirs, files in os.walk(config.SOPDS_ROOT_LIB, followlinks=True): # Если разрешена обработка inpx, то при нахождении inpx обрабатываем его и прекращаем обработку текущего каталога - if settings.INPX_ENABLE: + if config.SOPDS_INPX_ENABLE: inpx_files = [inpx for inpx in files if re.match('.*(.inpx|.INPX)$', inpx)] # Пропускаем обработку файлов в текущем каталоге, если найдены inpx if inpx_files: @@ -93,13 +96,13 @@ class opdsScanner: file=os.path.join(full_path,name) (n,e)=os.path.splitext(name) if (e.lower() == '.zip'): - if settings.ZIPSCAN: + if config.SOPDS_ZIPSCAN: self.processzip(name,full_path,file) else: file_size=os.path.getsize(file) self.processfile(name,full_path,file,None,0,file_size) - #if settings.DELETE_LOGICAL: + #if config.SOPDS_DELETE_LOGICAL: # self.books_deleted=opdsdb.books_del_logical() #else: # self.books_deleted=opdsdb.books_del_phisical() @@ -111,7 +114,7 @@ class opdsScanner: def inpskip_callback(self, inpx, inp_name, inp_size): self.zip_file = os.path.join(inpx,"%s%s"%(inp_name,'.zip')) - self.rel_path=os.path.relpath(self.zip_file,settings.ROOT_LIB) + self.rel_path=os.path.relpath(self.zip_file,config.SOPDS_ROOT_LIB) if opdsdb.arc_skip(self.rel_path,inp_size): self.logger.info('Skip ZIP for INP archive '+self.zip_file+'. Not changed.') @@ -150,20 +153,20 @@ class opdsScanner: opdsdb.addbseries(book,ser,0) def processinpx(self,name,full_path,file): - rel_file=os.path.relpath(file,settings.ROOT_LIB) + rel_file=os.path.relpath(file,config.SOPDS_ROOT_LIB) inpx_size = os.path.getsize(file) - if settings.INPX_SKIP_UNCHANGED and opdsdb.inpx_skip(rel_file,inpx_size): + if config.SOPDS_INPX_SKIP_UNCHANGED and opdsdb.inpx_skip(rel_file,inpx_size): self.logger.info('Skip INPX file = '+file+'. Not changed.') else: self.logger.info('Start process INPX file = '+file) opdsdb.addcattree(rel_file, opdsdb.CAT_INPX, inpx_size) inpx = inpx_parser.Inpx(file, self.inpx_callback, self.inpskip_callback) - inpx.INPX_TEST_ZIP = settings.INPX_TEST_ZIP - inpx.INPX_TEST_FILES = settings.INPX_TEST_FILES + inpx.INPX_TEST_ZIP = config.SOPDS_INPX_TEST_ZIP + inpx.INPX_TEST_FILES = config.SOPDS_INPX_TEST_FILES inpx.parse() def processzip(self,name,full_path,file): - rel_file=os.path.relpath(file,settings.ROOT_LIB) + rel_file=os.path.relpath(file,config.SOPDS_ROOT_LIB) zsize = os.path.getsize(file) if opdsdb.arc_skip(rel_file,zsize): self.arch_skipped+=1 @@ -193,8 +196,8 @@ class opdsScanner: def processfile(self,name,full_path,file,cat,archive=0,file_size=0): (n,e)=os.path.splitext(name) - if e.lower() in settings.BOOK_EXTENSIONS: - rel_path=os.path.relpath(full_path,settings.ROOT_LIB) + if e.lower() in config.SOPDS_BOOK_EXTENSIONS.split(): + rel_path=os.path.relpath(full_path,config.SOPDS_ROOT_LIB) self.logger.debug("Attempt to add book "+rel_path+"/"+name) self.fb2parser.reset() if opdsdb.findbook(name,rel_path,1)==None: @@ -206,7 +209,7 @@ class opdsScanner: docdate='' book_is_valid = True - if e.lower()=='.fb2' and settings.FB2PARSE: + if e.lower()=='.fb2' and config.SOPDS_FB2PARSE: if isinstance(file, str): f=open(file,'rb') else: diff --git a/opds_catalog/tests/test_feeds.py b/opds_catalog/tests/test_feeds.py index 5224dbabd550011f9f85ce7e314179e7c2b75b41..877b893a7d5980cd92ec712a49e9c6b0cb2cfe3d 100644 --- a/opds_catalog/tests/test_feeds.py +++ b/opds_catalog/tests/test_feeds.py @@ -4,14 +4,16 @@ from django.core.urlresolvers import reverse from django.test import TestCase, Client from django.utils.translation import ugettext as _ -from opds_catalog import settings, opdsdb +from opds_catalog import opdsdb +from opds_catalog import settings +from constance import config class feedsTestCase(TestCase): fixtures = ['testdb.json'] def setUp(self): - settings.AUTH=False + config.SOPDS_AUTH=False def test_MainFeed(self): c = Client() @@ -111,7 +113,7 @@ class feedsTestCase(TestCase): c = Client() response = c.get('/opds/books/0/') self.assertEquals(response.status_code, 200) - if settings.ALPHABET_MENU: + if config.SOPDS_ALPHABET_MENU: response = c.get(reverse('opds:lang_books')); self.assertEquals(response.status_code, 200) self.assertIn(_("Cyrillic"), response.content.decode()) @@ -122,7 +124,7 @@ class feedsTestCase(TestCase): c = Client() response = c.get('/opds/authors/0/') self.assertEquals(response.status_code, 200) - if settings.ALPHABET_MENU: + if config.SOPDS_ALPHABET_MENU: response = c.get(reverse('opds:lang_authors')); self.assertEquals(response.status_code, 200) self.assertIn(_("Cyrillic"), response.content.decode()) diff --git a/opds_catalog/tests/test_models.py b/opds_catalog/tests/test_models.py index 6240d5d063dbbad73881ba05be12baaec8a22dce..8c85181b76c264e0507202c55229216494c0a29c 100644 --- a/opds_catalog/tests/test_models.py +++ b/opds_catalog/tests/test_models.py @@ -3,7 +3,7 @@ from datetime import datetime from django.test import TestCase from django.utils import timezone from django.contrib.auth.models import User -from django.conf import settings +from django.conf import settings as main_settings from opds_catalog.models import Book, Catalog, Author, Genre, Series, bookshelf, Counter, bauthor, bgenre, bseries from opds_catalog import models @@ -11,7 +11,7 @@ from opds_catalog import opdsdb class modelsTestCase(TestCase): testdatetime = datetime(2016, 1, 1, 0, 0) - if settings.USE_TZ: + if main_settings.USE_TZ: testdatetime = testdatetime.replace(tzinfo=timezone.get_current_timezone()) def setUp(self): diff --git a/opds_catalog/tests/test_scan.py b/opds_catalog/tests/test_scan.py index fb123b4dc6ea9e41598d70a20e4fdd0719bcb859..b6a323c3704fef50c1aa7057920eecd643930a5a 100644 --- a/opds_catalog/tests/test_scan.py +++ b/opds_catalog/tests/test_scan.py @@ -4,9 +4,11 @@ from django.test import TestCase from opds_catalog import opdsdb from opds_catalog.sopdscan import opdsScanner -from opds_catalog import settings +#from opds_catalog import settings from opds_catalog.models import Book, Catalog, Author, Genre, Series +from constance import config + class scanTestCase(TestCase): test_module_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) test_ROOTLIB = os.path.join(test_module_path, 'tests/data') @@ -14,7 +16,7 @@ class scanTestCase(TestCase): test_zip = "books.zip" def setUp(self): - settings.ROOT_LIB = self.test_ROOTLIB + config.SOPDS_ROOT_LIB = self.test_ROOTLIB def test_processfile(self): """ Тестирование процедуры processfile (извлекает метаданные из книги и помещает в БД) """ diff --git a/sopds_web_backend/views.py b/sopds_web_backend/views.py index 797df3353fa82cfbe42cb921cb0b5bfdcc6619d1..578efc3a994fb498085e9cb623153fc0828d19e0 100644 --- a/sopds_web_backend/views.py +++ b/sopds_web_backend/views.py @@ -12,7 +12,8 @@ from django.core.urlresolvers import reverse, reverse_lazy from opds_catalog import models from opds_catalog.models import Book, Author, Series, bookshelf, Counter, Catalog, Genre #from opds_catalog.settings import MAXITEMS, DOUBLES_HIDE, AUTH, VERSION, ALPHABET_MENU, SPLITITEMS, FB2TOEPUB, FB2TOMOBI -from opds_catalog import settings as settings +from opds_catalog import settings +from constance import config from opds_catalog.models import lang_menu from opds_catalog.opds_paginator import Paginator as OPDS_Paginator @@ -20,7 +21,7 @@ from sopds_web_backend.settings import HALF_PAGES_LINKS def sopds_login(function=None, redirect_field_name=REDIRECT_FIELD_NAME, url=None): actual_decorator = user_passes_test( - lambda u: (u.is_authenticated() if settings.AUTH else True), + lambda u: (u.is_authenticated() if config.SOPDS_AUTH else True), login_url=reverse_lazy(url), redirect_field_name=redirect_field_name ) @@ -30,16 +31,16 @@ def sopds_login(function=None, redirect_field_name=REDIRECT_FIELD_NAME, url=None def sopds_processor(request): args={} - args['sopds_auth']=settings.AUTH + args['sopds_auth']=config.SOPDS_AUTH args['sopds_version']=settings.VERSION - args['alphabet'] = settings.ALPHABET_MENU - args['splititems'] = settings.SPLITITEMS - args['fb2tomobi'] = (settings.FB2TOMOBI!="") - args['fb2toepub'] = (settings.FB2TOEPUB!="") - if settings.ALPHABET_MENU: + args['alphabet'] = config.SOPDS_ALPHABET_MENU + args['splititems'] = config.SOPDS_SPLITITEMS + args['fb2tomobi'] = (config.SOPDS_FB2TOMOBI!="") + args['fb2toepub'] = (config.SOPDS_FB2TOEPUB!="") + if config.SOPDS_ALPHABET_MENU: args['lang_menu'] = lang_menu - if settings.AUTH: + if config.SOPDS_AUTH: user=request.user if user.is_authenticated(): result=[] @@ -137,7 +138,7 @@ def SearchBooksView(request): # Поиск книг на книжной полке elif searchtype == 'u': - if settings.AUTH: + if config.SOPDS_AUTH: books = Book.objects.filter(bookshelf__user=request.user).order_by('-bookshelf__readtime') args['breadcrumbs'] = [_('Books'),_('Bookshelf'),request.user.username] #books = bookshelf.objects.filter(user=request.user).select_related('book') @@ -176,7 +177,7 @@ def SearchBooksView(request): # Фильтруем дубликаты и формируем выдачу затребованной страницы books_count = books.count() - op = OPDS_Paginator(books_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(books_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS) items = [] prev_title = '' @@ -184,7 +185,7 @@ def SearchBooksView(request): # Начаинам анализ с последнего элемента на предидущей странице, чторбы он "вытянул" с этой страницы # свои дубликаты если они есть - summary_DOUBLES_HIDE = settings.DOUBLES_HIDE and (searchtype != 'd') + summary_DOUBLES_HIDE = config.SOPDS_DOUBLES_HIDE and (searchtype != 'd') start = op.d1_first_pos if ((op.d1_first_pos==0) or (not summary_DOUBLES_HIDE)) else op.d1_first_pos-1 finish = op.d1_last_pos @@ -252,7 +253,7 @@ def SearchSeriesView(request): # Создаем результирующее множество series_count = series.count() - op = OPDS_Paginator(series_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(series_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS) items = [] for row in series[op.d1_first_pos:op.d1_last_pos+1]: #p = {'id':row.id, 'ser':row.ser, 'lang_code': row.lang_code, 'book_count': Book.objects.filter(series=row).count()} @@ -291,7 +292,7 @@ def SearchAuthorsView(request): # Создаем результирующее множество authors_count = authors.count() - op = OPDS_Paginator(authors_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(authors_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS) items = [] for row in authors[op.d1_first_pos:op.d1_last_pos+1]: @@ -335,7 +336,7 @@ def CatalogsView(request): books_count = books_list.count() # Получаем результирующий список - op = OPDS_Paginator(catalogs_count, books_count, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(catalogs_count, books_count, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS) items = [] for row in catalogs_list[op.d1_first_pos:op.d1_last_pos+1]: