From e554d36bd0dd1faa5ea80d0ebd472f9e7db6a4a6 Mon Sep 17 00:00:00 2001 From: Dmitry Shelepnev <mitshel@mail.ru> Date: Sat, 7 Jan 2017 20:42:39 +0300 Subject: [PATCH] Move all SOPDS settings to database --- .../management/commands/sopds_scanner.py | 19 ++--- .../management/commands/sopds_server.py | 9 ++- opds_catalog/settings.py | 77 +++++++++++-------- sopds/settings.py | 19 ----- sopds_web_backend/views.py | 33 ++++---- 5 files changed, 78 insertions(+), 79 deletions(-) diff --git a/opds_catalog/management/commands/sopds_scanner.py b/opds_catalog/management/commands/sopds_scanner.py index e16c6fe..f75be29 100644 --- a/opds_catalog/management/commands/sopds_scanner.py +++ b/opds_catalog/management/commands/sopds_scanner.py @@ -8,11 +8,12 @@ from apscheduler.schedulers.blocking import BlockingScheduler from django.core.management.base import BaseCommand from django.db import transaction, connection, connections -from django.conf import settings +from django.conf import settings as main_settings 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.settings import SCANNER_LOG, SCAN_SHED_DAY, SCAN_SHED_DOW, SCAN_SHED_HOUR, SCAN_SHED_MIN, LOGLEVEL, SCANNER_PID +from opds_catalog import settings class Command(BaseCommand): help = 'Scan Books Collection.' @@ -23,16 +24,16 @@ 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(settings.BASE_DIR, SCANNER_PID) + self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SCANNER_PID) action = options['command'] self.logger = logging.getLogger('') self.logger.setLevel(logging.DEBUG) formatter=logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') - if LOGLEVEL!=logging.NOTSET: + if settings.LOGLEVEL!=logging.NOTSET: # Создаем обработчик для записи логов в файл - fh = logging.FileHandler(SCANNER_LOG) - fh.setLevel(LOGLEVEL) + fh = logging.FileHandler(settings.SCANNER_LOG) + fh.setLevel(settings.LOGLEVEL) fh.setFormatter(formatter) self.logger.addHandler(fh) @@ -76,9 +77,9 @@ class Command(BaseCommand): def start(self): writepid(self.pidfile) - self.stdout.write('Startup scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(SCAN_SHED_MIN,SCAN_SHED_HOUR,SCAN_SHED_DOW,SCAN_SHED_DAY)) + self.stdout.write('Startup scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(settings.SCAN_SHED_MIN,settings.SCAN_SHED_HOUR,settings.SCAN_SHED_DOW,settings.SCAN_SHED_DAY)) sched = BlockingScheduler() - sched.add_job(self.scan, 'cron', day=SCAN_SHED_DAY, day_of_week=SCAN_SHED_DOW, hour=SCAN_SHED_HOUR, minute=SCAN_SHED_MIN) + sched.add_job(self.scan, 'cron', day=settings.SCAN_SHED_DAY, day_of_week=settings.SCAN_SHED_DOW, hour=settings.SCAN_SHED_HOUR, minute=settings.SCAN_SHED_MIN) quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C' self.stdout.write("Quit the server with %s.\n"%quit_command) try: @@ -118,7 +119,7 @@ def daemonize(): os.umask(0) std_in = open("/dev/null", 'r') - std_out = open(SCANNER_LOG, 'a+') + std_out = open(settings.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 dceee88..6803071 100644 --- a/opds_catalog/management/commands/sopds_server.py +++ b/opds_catalog/management/commands/sopds_server.py @@ -2,11 +2,12 @@ import os import signal import sys -from django.conf import settings +from django.conf import settings as main_settings 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.settings import SERVER_LOG, SERVER_PID +from opds_catalog import settings class Command(BaseCommand): help = 'HTTP/OPDS built-in server' @@ -19,7 +20,7 @@ class Command(BaseCommand): def handle(self, *args, **options): - self.pidfile = os.path.join(settings.BASE_DIR, SERVER_PID) + self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SERVER_PID) action = options['command'] self.addr = options['host'] self.port = int(options['port']) @@ -75,7 +76,7 @@ def daemonize(): os.umask(0) std_in = open("/dev/null", 'r') - std_out = open(SERVER_LOG, 'a+') + std_out = open(settings.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/settings.py b/opds_catalog/settings.py index c719a5b..81242f7 100644 --- a/opds_catalog/settings.py +++ b/opds_catalog/settings.py @@ -1,30 +1,31 @@ import logging import os from django.conf import settings +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.39" +VERSION = "0.40" # ROOT_LIB содержит путь к каталогу в котором расположена ваша коллекция книг -ROOT_LIB = getattr(settings, "SOPDS_ROOT_LIB", "books/") +ROOT_LIB = config.SOPDS_ROOT_LIB # Списк форматов книг, которые будут включаться в каталог -BOOK_EXTENSIONS = getattr(settings, "SOPDS_BOOK_EXTESIONS", ['.pdf', '.djvu', '.fb2', '.epub']) +BOOK_EXTENSIONS = config.SOPDS_BOOK_EXTENSIONS.split() # Скрывает, найденные дубликаты в выдачах книг -DOUBLES_HIDE = getattr(settings, "SOPDS_DOUBLES_HIDE", True) +DOUBLES_HIDE = config.SOPDS_DOUBLES_HIDE # Извлекать метаинформацию из книг fb2 -FB2PARSE = getattr(settings, "SOPDS_FB2PARSE", True) +FB2PARSE = config.SOPDS_FB2PARSE # cover_show - способ показа обложек: # False - не показывать, # True - извлекать обложки на лету и показывать -COVER_SHOW = getattr(settings, "SOPDS_COVER_SHOW", True) +COVER_SHOW = config.SOPDS_COVER_SHOW # ZIPSCAN = True - Приводит к сканированию файлов архива -ZIPSCAN = getattr(settings, "SOPDS_ZIPSCAN", True) +ZIPSCAN = config.SOPDS_ZIPSCAN # Указываем какая кодировка для названий файлов используется в ZIP-архивах # доступные кодировки: cp437, cp866, cp1251, utf-8 @@ -33,73 +34,73 @@ ZIPSCAN = getattr(settings, "SOPDS_ZIPSCAN", True) # то автоматически определить правильную кодировку для имен файлов не представляется возможным # поэтому для того чтобы кириллические имена файлов не ваыглядели как крякозябры следует применять кодировку cp866 # по умолчанию также используется значение zip_codepage = cp866 -ZIPCODEPAGE = getattr(settings, "SOPDS_ZIPCODEPAGE", "cp866") +ZIPCODEPAGE = config.SOPDS_ZIPCODEPAGE # Если INPX_ENABLE = True, то при обнаружении INPX файла в каталоге, сканер не сканирует его содержимое вместе с подгаталогами, а загружает # данные из найденного INPX файла. Сканер считает что сами архивыс книгами расположены в этом же каталоге. # Т.е. INPX-файл должен находится именно в папке с архивами книг -INPX_ENABLE = getattr(settings, "SOPDS_INPX_ENABLE", True) +INPX_ENABLE = config.SOPDS_INPX_ENABLE # Если INPX_SKIP_UNCHANGED = True, то сканер пропускает повторное сканирование, если размер INPX не изменялся -INPX_SKIP_UNCHANGED = getattr(settings, "SOPDS_INPX_SKIP_UNCHANGED", True) +INPX_SKIP_UNCHANGED = config.SOPDS_INPX_SKIP_UNCHANGED # Если INPX_TEST_ZIP = True, то сканер пытается найти описанный в INPX архив. Если какой-то архив не обнаруживается, # то сканер не будет добавлять вязанные с ним данные из INPX в базу данных # соответсвенно, если INPX_TEST_ZIP = False, то никаких проверок сканер не производит, а просто добавляет данные из INPX в БД # это гораздо быстрее -INPX_TEST_ZIP = getattr(settings, "SOPDS_INPX_TEST_ZIP", False) +INPX_TEST_ZIP = config.SOPDS_INPX_TEST_ZIP # Если INPX_TEST_FILES = True, то сканер пытается найти описанный в INPX конкретный файл с книгой (уже внутри архивов). Если какой-то файл не обнаруживается, # то сканер не будет добавлять эту книгу в базу данных # соответсвенно, если INPX_TEST_FILES = False, то никаких проверок сканер не производит, а просто добавляет книгу из INPX в БД # это гораздо быстрее -INPX_TEST_FILES = getattr(settings, "SOPDS_TEST_FILES", False) +INPX_TEST_FILES = config.SOPDS_INPX_TEST_FILES # Установка DELETE_LOGICAL=True приведет к тому, что при обнаружении сканером, что книга удалена, запись в БД об этой книге будет удалена логически (avail=0) # Если DELETE_LOGICAL=False, то произойдет физическое удаление таких записей из базы данных # пока работает только DELETE_LOGICAL = False -DELETE_LOGICAL = getattr(settings, "SOPDS_DELETE_LOGICAL", False) +DELETE_LOGICAL = config.SOPDS_DELETE_LOGICAL -SPLITITEMS = getattr(settings, "SOPDS_SPLITITEMS", 300) +SPLITITEMS = config.SOPDS_SPLITITEMS # Количество выдаваемых результатов на одну страницу -MAXITEMS = getattr(settings, "SOPDS_MAXITEMS", 60) +MAXITEMS = config.SOPDS_MAXITEMS # FB2TOEPUB и FB2TOMOBI задают пути к програмам - конвертерам из FB2 в EPUB и MOBI -FB2TOEPUB = getattr(settings, "SOPDS_FB2TOEPUB", "") -FB2TOMOBI = getattr(settings, "SOPDS_FB2TOMOBI", "") +FB2TOEPUB = config.SOPDS_FB2TOEPUB +FB2TOMOBI = config.SOPDS_FB2TOMOBI # TEMP_DIR задает путь к временному каталогу, который используется для копирования оригинала и результата конвертации -TEMP_DIR = getattr(settings, "SOPDS_TEMP_DIR", os.path.join(settings.BASE_DIR,'tmp')) +TEMP_DIR = config.SOPDS_TEMP_DIR # При скачивании вместо оригинального имени файла книги выдает транслитерацию названия книги -TITLE_AS_FILENAME = getattr(settings, "SOPDS_TITLE_AS_FILENAME", True) +TITLE_AS_FILENAME = config.SOPDS_TITLE_AS_FILENAME # Включение дополнительного меню выбора алфавита -ALPHABET_MENU = getattr(settings, "SOPDS_ALPHABET_MENU", True) +ALPHABET_MENU = config.SOPDS_ALPHABET_MENU # Обложка, которая будет демонстрироваться для книг без обложек -NOCOVER_PATH = getattr(settings, "SOPDS_NOCOVER_PATH", os.path.join(settings.BASE_DIR,'static/images/nocover.jpg')) +NOCOVER_PATH = config.SOPDS_NOCOVER_PATH # Включение BASIC - авторизации -AUTH = getattr(settings, "SOPDS_AUTH", False) +AUTH = config.SOPDS_AUTH # параметры SERVER_LOG и SCANNER_LOG задают размещение LOG файлов этих процессов -SERVER_LOG = getattr(settings, "SOPDS_SERVER_LOG", os.path.join(settings.BASE_DIR,'opds_catalog/log/sopds_server.log')) -SCANNER_LOG = getattr(settings, "SOPDS_SCANNER_LOG", os.path.join(settings.BASE_DIR,'opds_catalog/log/sopds_scanner.log')) +SERVER_LOG = config.SOPDS_SERVER_LOG +SCANNER_LOG = config.SOPDS_SCANNER_LOG # параметры SERVER_PID и SCANNER_PID задают размещение PID файлов этих процессов при демонизации -SERVER_PID = getattr(settings, "SOPDS_SERVER_PID", os.path.join(settings.BASE_DIR,'opds_catalog/tmp/sopds_server.pid')) -SCANNER_PID = getattr(settings, "SOPDS_SCANNER_PID", os.path.join(settings.BASE_DIR,'opds_catalog/tmp/sopds_scanner.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 = getattr(settings, "SOPDS_SCAN_SHED_MIN", '0') -SCAN_SHED_HOUR = getattr(settings, "SOPDS_SCAN_SHED_HOUR", '0') -SCAN_SHED_DAY = getattr(settings, "SOPDS_SCAN_SHED_DAY", '*') -SCAN_SHED_DOW = getattr(settings, "SOPDS_SCAN_SHED_DOW", '*') +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) @@ -111,9 +112,23 @@ 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) + print(key, value, MAXITEMS) + # Переопределяем некоторые функции для SQLite, которые работают неправлено from django.db.backends.signals import connection_created -from django.dispatch import receiver def sopds_upper(s): return s.upper() diff --git a/sopds/settings.py b/sopds/settings.py index 39490ed..d600f35 100644 --- a/sopds/settings.py +++ b/sopds/settings.py @@ -195,23 +195,4 @@ CONSTANCE_CONFIG_FIELDSETS = { '6. Log & PID Files': ('SOPDS_SERVER_LOG', 'SOPDS_SCANNER_LOG', 'SOPDS_SERVER_PID','SOPDS_SCANNER_PID'), } -# -# SIMPLE OPDS SETTINGS -# -SOPDS_ROOT_LIB = 'W:\\_Downloads\\_Lib.rus.ec - Официальная\\lib.rus.ec\\' -#SOPDS_ROOT_LIB = '/mnt/SATA1TB-1/КНИГИ/BOOKS/' -#SOPDS_ROOT_LIB = '/mnt/nfs/КНИГИ/BOOKS/' -#SOPDS_ROOT_LIB = os.path.join(BASE_DIR,'opds_catalog\\tests\\data\\') -#SOPDS_ROOT_LIB = "d:\\BOOKS\\" - -SOPDS_AUTH = True -SOPDS_SCAN_SHED_MIN ='0' -SOPDS_SCAN_SHED_HOUR ='0,12' -SOPDS_INPX_ENABLE = True - -#Конвертеры EPUB и MOBI -#SOPDS_FB2TOEPUB = os.path.join(BASE_DIR,'convert/fb2toepub/unix_dist/fb2toepub') -#SOPDS_FB2TOEPUB = os.path.join(BASE_DIR,'convert/fb2conv/fb2epub') -#SOPDS_FB2TOMOBI = os.path.join(BASE_DIR,'convert/fb2conv/fb2mobi') -#SOPDS_FB2TOEPUB = os.path.join(BASE_DIR, 'convert\\fb2epub\\fb2epub.cmd' if sys.platform =='win32' else 'convert/fb2epub/fb2epub' ) diff --git a/sopds_web_backend/views.py b/sopds_web_backend/views.py index 367bb91..797df33 100644 --- a/sopds_web_backend/views.py +++ b/sopds_web_backend/views.py @@ -11,7 +11,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.settings import MAXITEMS, DOUBLES_HIDE, AUTH, VERSION, ALPHABET_MENU, SPLITITEMS, FB2TOEPUB, FB2TOMOBI +from opds_catalog import settings as settings from opds_catalog.models import lang_menu from opds_catalog.opds_paginator import Paginator as OPDS_Paginator @@ -19,7 +20,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 AUTH else True), + lambda u: (u.is_authenticated() if settings.AUTH else True), login_url=reverse_lazy(url), redirect_field_name=redirect_field_name ) @@ -29,16 +30,16 @@ def sopds_login(function=None, redirect_field_name=REDIRECT_FIELD_NAME, url=None def sopds_processor(request): args={} - args['sopds_auth']=AUTH - args['sopds_version']=VERSION - args['alphabet'] = ALPHABET_MENU - args['splititems'] = SPLITITEMS - args['fb2tomobi'] = (FB2TOMOBI!="") - args['fb2toepub'] = (FB2TOEPUB!="") - if ALPHABET_MENU: + args['sopds_auth']=settings.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['lang_menu'] = lang_menu - if AUTH: + if settings.AUTH: user=request.user if user.is_authenticated(): result=[] @@ -136,7 +137,7 @@ def SearchBooksView(request): # Поиск книг на книжной полке elif searchtype == 'u': - if AUTH: + if settings.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') @@ -175,7 +176,7 @@ def SearchBooksView(request): # Фильтруем дубликаты и формируем выдачу затребованной страницы books_count = books.count() - op = OPDS_Paginator(books_count, 0, page_num, MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(books_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) items = [] prev_title = '' @@ -183,7 +184,7 @@ def SearchBooksView(request): # Начаинам анализ с последнего элемента на предидущей странице, чторбы он "вытянул" с этой страницы # свои дубликаты если они есть - summary_DOUBLES_HIDE = DOUBLES_HIDE and (searchtype != 'd') + summary_DOUBLES_HIDE = settings.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 @@ -251,7 +252,7 @@ def SearchSeriesView(request): # Создаем результирующее множество series_count = series.count() - op = OPDS_Paginator(series_count, 0, page_num, MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(series_count, 0, page_num, settings.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()} @@ -290,7 +291,7 @@ def SearchAuthorsView(request): # Создаем результирующее множество authors_count = authors.count() - op = OPDS_Paginator(authors_count, 0, page_num, MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(authors_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) items = [] for row in authors[op.d1_first_pos:op.d1_last_pos+1]: @@ -334,7 +335,7 @@ def CatalogsView(request): books_count = books_list.count() # Получаем результирующий список - op = OPDS_Paginator(catalogs_count, books_count, page_num, MAXITEMS, HALF_PAGES_LINKS) + op = OPDS_Paginator(catalogs_count, books_count, page_num, settings.MAXITEMS, HALF_PAGES_LINKS) items = [] for row in catalogs_list[op.d1_first_pos:op.d1_last_pos+1]: -- GitLab