Commit e554d36b authored by Dmitry Shelepnev's avatar Dmitry Shelepnev
Browse files

Move all SOPDS settings to database

parent 5c3bfc2f
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -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())    
+5 −4
Original line number Diff line number Diff line
@@ -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())    
+46 −31
Original line number Diff line number Diff line
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()
+0 −19
Original line number Diff line number Diff line
@@ -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' )
+17 −16
Original line number Diff line number Diff line
@@ -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]: