reasonably working calibreweb thing
This commit is contained in:
commit
8ec8c686c6
0
CalibreWebCompanion/CalibreWebCompanion/__init__.py
Normal file
0
CalibreWebCompanion/CalibreWebCompanion/__init__.py
Normal file
16
CalibreWebCompanion/CalibreWebCompanion/asgi.py
Normal file
16
CalibreWebCompanion/CalibreWebCompanion/asgi.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for CalibreWebCompanion project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CalibreWebCompanion.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
137
CalibreWebCompanion/CalibreWebCompanion/settings.py
Normal file
137
CalibreWebCompanion/CalibreWebCompanion/settings.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
"""
|
||||||
|
Django settings for CalibreWebCompanion project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 3.0.8.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
CALIBRE_DIR = os.path.abspath("C:\\Users\\MassiveAtoms\\Documents\\Calibre Library")
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'u(8^+rb%rz5hsx4v^^y(ul7g(4n7a8!db@s*9(m5cs*2_ppy8+'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
"library"
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'CalibreWebCompanion.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [
|
||||||
|
os.path.join(BASE_DIR, 'templates'),
|
||||||
|
],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'CalibreWebCompanion.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
},
|
||||||
|
'calibre': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(CALIBRE_DIR, 'metadata.db'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DATABASE_ROUTERS = ["db_routers.DjangoRouter", "db_routers.CalibreRouter"]
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'America/Paramaribo'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
os.path.abspath(CALIBRE_DIR),
|
||||||
|
# '/static/',
|
||||||
|
]
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
27
CalibreWebCompanion/CalibreWebCompanion/urls.py
Normal file
27
CalibreWebCompanion/CalibreWebCompanion/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""CalibreWebCompanion URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/3.0/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
path('library/', include('library.urls')),
|
||||||
|
path('', RedirectView.as_view(url='library/', permanent=True)),
|
||||||
|
]
|
||||||
|
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
16
CalibreWebCompanion/CalibreWebCompanion/wsgi.py
Normal file
16
CalibreWebCompanion/CalibreWebCompanion/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for CalibreWebCompanion project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CalibreWebCompanion.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
BIN
CalibreWebCompanion/db.sqlite3
Normal file
BIN
CalibreWebCompanion/db.sqlite3
Normal file
Binary file not shown.
2
CalibreWebCompanion/db_routers/__init__.py
Normal file
2
CalibreWebCompanion/db_routers/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .routers import DjangoRouter, CalibreRouter
|
||||||
|
__name__ = "db_routers"
|
76
CalibreWebCompanion/db_routers/routers.py
Normal file
76
CalibreWebCompanion/db_routers/routers.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class DjangoRouter:
|
||||||
|
"""
|
||||||
|
A router to control all database operations on models in the
|
||||||
|
auth and contenttypes applications.
|
||||||
|
"""
|
||||||
|
route_app_labels = {'auth', 'contenttypes', "sessions", "sites", "admin", "flatpages"}
|
||||||
|
|
||||||
|
def db_for_read(self, model, **hints):
|
||||||
|
"""
|
||||||
|
Attempts to read auth and contenttypes models go to default.
|
||||||
|
"""
|
||||||
|
if model._meta.app_label in self.route_app_labels:
|
||||||
|
return 'default'
|
||||||
|
return None
|
||||||
|
|
||||||
|
def db_for_write(self, model, **hints):
|
||||||
|
"""
|
||||||
|
Attempts to write auth and contenttypes models go to django.
|
||||||
|
"""
|
||||||
|
if model._meta.app_label in self.route_app_labels:
|
||||||
|
return 'default'
|
||||||
|
return None
|
||||||
|
|
||||||
|
def allow_relation(self, obj1, obj2, **hints):
|
||||||
|
"""
|
||||||
|
Allow relations if a model in the auth or contenttypes apps is
|
||||||
|
involved.
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
obj1._meta.app_label in self.route_app_labels or
|
||||||
|
obj2._meta.app_label in self.route_app_labels
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|
||||||
|
def allow_migrate(self, db, app_label, model_name=None, **hints):
|
||||||
|
"""
|
||||||
|
Make sure the auth and contenttypes apps only appear in the
|
||||||
|
'django' database.
|
||||||
|
"""
|
||||||
|
if app_label in self.route_app_labels:
|
||||||
|
return db == 'default'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CalibreRouter:
|
||||||
|
"""
|
||||||
|
A router to control all database operations on models in the
|
||||||
|
auth and contenttypes applications.
|
||||||
|
"""
|
||||||
|
def db_for_read(self, model, **hints):
|
||||||
|
"""
|
||||||
|
Attempts to read anything else goes to calibre
|
||||||
|
"""
|
||||||
|
return 'calibre'
|
||||||
|
|
||||||
|
# def db_for_write(self, model, **hints): # might be prudent not to allow writes
|
||||||
|
# """
|
||||||
|
# Attempts to write auth and contenttypes models go to 'calibre'.
|
||||||
|
# """
|
||||||
|
# return 'calibre'
|
||||||
|
|
||||||
|
def allow_relation(self, obj1, obj2, **hints):
|
||||||
|
"""
|
||||||
|
Allow relations.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
# def allow_migrate(self, db, app_label, model_name=None, **hints): # might be prudent not to allow migrations
|
||||||
|
# """
|
||||||
|
# Yes
|
||||||
|
# """
|
||||||
|
# return True
|
0
CalibreWebCompanion/library/__init__.py
Normal file
0
CalibreWebCompanion/library/__init__.py
Normal file
265
CalibreWebCompanion/library/_models.py
Normal file
265
CalibreWebCompanion/library/_models.py
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# This is an auto-generated Django model module.
|
||||||
|
# You'll have to do the following manually to clean this up:
|
||||||
|
# * Rearrange models' order
|
||||||
|
# * Make sure each model has one field with primary_key=True
|
||||||
|
# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
|
||||||
|
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
|
||||||
|
# Feel free to rename the models, but don't rename db_table values or field names.
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Authors(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
link = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'authors'
|
||||||
|
|
||||||
|
|
||||||
|
class Comments(models.Model):
|
||||||
|
book = models.ForeignField("Book")
|
||||||
|
text = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'comments'
|
||||||
|
|
||||||
|
|
||||||
|
class Data(models.Model):
|
||||||
|
book = models.IntegerField()
|
||||||
|
format = models.TextField()
|
||||||
|
uncompressed_size = models.IntegerField()
|
||||||
|
name = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'data'
|
||||||
|
|
||||||
|
|
||||||
|
class Identifiers(models.Model):
|
||||||
|
book = models.IntegerField()
|
||||||
|
type = models.TextField()
|
||||||
|
val = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'identifiers'
|
||||||
|
|
||||||
|
|
||||||
|
class Languages(models.Model):
|
||||||
|
lang_code = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'languages'
|
||||||
|
|
||||||
|
|
||||||
|
class Publishers(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'publishers'
|
||||||
|
|
||||||
|
|
||||||
|
class Ratings(models.Model):
|
||||||
|
rating = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'ratings'
|
||||||
|
|
||||||
|
|
||||||
|
class Series(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'series'
|
||||||
|
|
||||||
|
|
||||||
|
class Tags(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'tags'
|
||||||
|
|
||||||
|
|
||||||
|
class Books(models.Model):
|
||||||
|
title = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
# This field type is a guess.
|
||||||
|
timestamp = models.TextField(blank=True, null=True)
|
||||||
|
# This field type is a guess.
|
||||||
|
pubdate = models.TextField(blank=True, null=True)
|
||||||
|
series_index = models.FloatField()
|
||||||
|
author_sort = models.TextField(blank=True, null=True)
|
||||||
|
isbn = models.TextField(blank=True, null=True)
|
||||||
|
lccn = models.TextField(blank=True, null=True)
|
||||||
|
path = models.TextField()
|
||||||
|
flags = models.IntegerField()
|
||||||
|
uuid = models.TextField(blank=True, null=True)
|
||||||
|
has_cover = models.BooleanField(blank=True, null=True)
|
||||||
|
last_modified = models.TextField() # This field type is a guess.
|
||||||
|
authors = models.ManyToManyField(
|
||||||
|
Authors,
|
||||||
|
through='BooksAuthorsLink',
|
||||||
|
through_fields=('book', 'author'))
|
||||||
|
languages = models.ManyToManyField(
|
||||||
|
Languages,
|
||||||
|
through='BooksLanguagesLink',
|
||||||
|
through_fields=('book', 'lang_code'))
|
||||||
|
publishers = models.ManyToManyField(
|
||||||
|
Publishers,
|
||||||
|
through='BooksPublishersLink',
|
||||||
|
through_fields=('book', 'publisher'))
|
||||||
|
series = models.ManyToManyField(
|
||||||
|
Series,
|
||||||
|
through='BooksSeriesLink',
|
||||||
|
through_fields=('book', 'series'))
|
||||||
|
tags = models.ManyToManyField(
|
||||||
|
Tags,
|
||||||
|
through='BooksTagsLink',
|
||||||
|
through_fields=('book', 'tag'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksAuthorsLink(models.Model):
|
||||||
|
book = models.ForeignKey(db_column="book")
|
||||||
|
author = models.ForeignKey(db_column="author")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_authors_link'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksLanguagesLink(models.Model):
|
||||||
|
book = models.ForeignKey(db_colum="book")
|
||||||
|
lang_code = models.ForeignKey(db_column="lang_code")
|
||||||
|
item_order = models.IntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_languages_link'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksPublishersLink(models.Model):
|
||||||
|
book = models.ForeignKey(db_column="book")
|
||||||
|
publisher = models.ForeignKey(db_column="publisher")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_publishers_link'
|
||||||
|
|
||||||
|
|
||||||
|
# class BooksRatingsLink(models.Model): # TODO add this somehow
|
||||||
|
# book = models.ForeignKey(db_column="book")
|
||||||
|
# rating = models.IntegerField()
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'books_ratings_link'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksSeriesLink(models.Model):
|
||||||
|
book = models.ForeignKey(db_column="book")
|
||||||
|
series = models.ForeignKey(db_column="series")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_series_link'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksTagsLink(models.Model):
|
||||||
|
book = models.ForeignKey(db_column="book")
|
||||||
|
tag = models.ForeignKey(db_column="tag")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_tags_link'
|
||||||
|
|
||||||
|
|
||||||
|
# class BooksPluginData(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
# name = models.TextField()
|
||||||
|
# val = models.TextField()
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'books_plugin_data'
|
||||||
|
|
||||||
|
|
||||||
|
# class ConversionOptions(models.Model):
|
||||||
|
# format = models.TextField()
|
||||||
|
# book = models.IntegerField(blank=True, null=True)
|
||||||
|
# data = models.BinaryField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'conversion_options'
|
||||||
|
#
|
||||||
|
# class LibraryId(models.Model):
|
||||||
|
# uuid = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'library_id'
|
||||||
|
#
|
||||||
|
# class CustomColumns(models.Model):
|
||||||
|
# label = models.TextField()
|
||||||
|
# name = models.TextField()
|
||||||
|
# datatype = models.TextField()
|
||||||
|
# mark_for_delete = models.BooleanField()
|
||||||
|
# editable = models.BooleanField()
|
||||||
|
# display = models.TextField()
|
||||||
|
# is_multiple = models.BooleanField()
|
||||||
|
# normalized = models.BooleanField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'custom_columns'
|
||||||
|
#
|
||||||
|
# class Preferences(models.Model):
|
||||||
|
# key = models.TextField()
|
||||||
|
# val = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'preferences'
|
||||||
|
#
|
||||||
|
# class Feeds(models.Model):
|
||||||
|
# title = models.TextField()
|
||||||
|
# script = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'feeds'
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# class LastReadPositions(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
# format = models.TextField()
|
||||||
|
# user = models.TextField()
|
||||||
|
# device = models.TextField()
|
||||||
|
# cfi = models.TextField()
|
||||||
|
# epoch = models.FloatField()
|
||||||
|
# pos_frac = models.FloatField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'last_read_positions'
|
||||||
|
|
||||||
|
|
||||||
|
# class MetadataDirtied(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'metadata_dirtied'
|
27
CalibreWebCompanion/library/admin.py
Normal file
27
CalibreWebCompanion/library/admin.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import Authors, Books, Languages, Publishers, Series, Tags
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
@admin.register(Authors)
|
||||||
|
class AuthorAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["name"])
|
||||||
|
|
||||||
|
@admin.register(Languages)
|
||||||
|
class LanguageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["id", "lang_code"])
|
||||||
|
|
||||||
|
@admin.register(Publishers)
|
||||||
|
class PublisherAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["id","name"])
|
||||||
|
|
||||||
|
@admin.register(Series)
|
||||||
|
class SeriesAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["id","name"])
|
||||||
|
|
||||||
|
@admin.register(Tags)
|
||||||
|
class TagAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["id","name"])
|
||||||
|
|
||||||
|
@admin.register(Books)
|
||||||
|
class BookAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (["id","title", "author_sort"])
|
5
CalibreWebCompanion/library/apps.py
Normal file
5
CalibreWebCompanion/library/apps.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryConfig(AppConfig):
|
||||||
|
name = 'library'
|
107
CalibreWebCompanion/library/calibredb.py
Normal file
107
CalibreWebCompanion/library/calibredb.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
engine = create_engine('sqlite:///C://Users//MassiveAtoms//Documents//Calibre Library//metadata.db.', echo=True)
|
||||||
|
Base = declarative_base(engine)
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
class Author(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'authors'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, text name, sort
|
||||||
|
|
||||||
|
class Comment(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'comments'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, int book, text text
|
||||||
|
|
||||||
|
# class Data(Base): # maybe
|
||||||
|
# """"""
|
||||||
|
# __tablename__ = 'data'
|
||||||
|
# __table_args__ = {'autoload':True}
|
||||||
|
# # has int id, int book, text format, text name
|
||||||
|
|
||||||
|
class Identifier(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'identifiers'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, int book, text value
|
||||||
|
|
||||||
|
class Publisher(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'publishers'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, text name
|
||||||
|
|
||||||
|
class Rating(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'ratings'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, int rating
|
||||||
|
|
||||||
|
class Series(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'series'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, text name
|
||||||
|
|
||||||
|
class Tag(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'tags'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, text name
|
||||||
|
|
||||||
|
class Book(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, text title, text sort, time timestamp, time pubdate,
|
||||||
|
# float series_index, text path
|
||||||
|
|
||||||
|
class Book_author_link(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books_authors_link'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, id book, id author
|
||||||
|
|
||||||
|
class Book_publisher_link(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books_publishers_link'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, id book, id publisher
|
||||||
|
|
||||||
|
class Book_rating_link(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books_ratings_link'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, id book, id rating
|
||||||
|
|
||||||
|
class Book_series_link(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books_series_link'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, id book, id series
|
||||||
|
|
||||||
|
class Book_tags_link(Base): # needed
|
||||||
|
""""""
|
||||||
|
__tablename__ = 'books_tags_link'
|
||||||
|
__table_args__ = {'autoload':True}
|
||||||
|
# has int id, id book, id tag
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def loadSession():
|
||||||
|
""""""
|
||||||
|
metadata = Base.metadata
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
session = Session()
|
||||||
|
return session
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
session = loadSession()
|
||||||
|
res = session.query(Book).all()
|
||||||
|
for i in res:
|
||||||
|
print(i.id, i.title, i.sort, i.timestamp, i.pubdate, i.series_index, i.path)
|
||||||
|
|
206
CalibreWebCompanion/library/migrations/0001_initial.py
Normal file
206
CalibreWebCompanion/library/migrations/0001_initial.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# Generated by Django 3.0.8 on 2020-07-07 17:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Authors',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField()),
|
||||||
|
('sort', models.TextField(blank=True, null=True)),
|
||||||
|
('link', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'authors',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Books',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.TextField()),
|
||||||
|
('sort', models.TextField(blank=True, null=True)),
|
||||||
|
('timestamp', models.TextField(blank=True, null=True)),
|
||||||
|
('pubdate', models.TextField(blank=True, null=True)),
|
||||||
|
('series_index', models.FloatField()),
|
||||||
|
('author_sort', models.TextField(blank=True, null=True)),
|
||||||
|
('isbn', models.TextField(blank=True, null=True)),
|
||||||
|
('lccn', models.TextField(blank=True, null=True)),
|
||||||
|
('path', models.TextField()),
|
||||||
|
('flags', models.IntegerField()),
|
||||||
|
('uuid', models.TextField(blank=True, null=True)),
|
||||||
|
('has_cover', models.BooleanField(blank=True, null=True)),
|
||||||
|
('last_modified', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksAuthorsLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_authors_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksLanguagesLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('item_order', models.IntegerField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_languages_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksPublishersLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_publishers_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksRatingsLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_ratings_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksSeriesLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_series_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BooksTagsLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'books_tags_link',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Comments',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('text', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'comments',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('book', models.IntegerField()),
|
||||||
|
('format', models.TextField()),
|
||||||
|
('uncompressed_size', models.IntegerField()),
|
||||||
|
('name', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'data',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Identifiers',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('book', models.IntegerField()),
|
||||||
|
('type', models.TextField()),
|
||||||
|
('val', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'identifiers',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Languages',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('lang_code', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'languages',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Publishers',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField()),
|
||||||
|
('sort', models.TextField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'publishers',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Ratings',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('rating', models.IntegerField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'ratings',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Series',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField()),
|
||||||
|
('sort', models.TextField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'series',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tags',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'tags',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
CalibreWebCompanion/library/migrations/__init__.py
Normal file
0
CalibreWebCompanion/library/migrations/__init__.py
Normal file
387
CalibreWebCompanion/library/models.py
Normal file
387
CalibreWebCompanion/library/models.py
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
# This is an auto-generated Django model module.
|
||||||
|
# You'll have to do the following manually to clean this up:
|
||||||
|
# * Rearrange models' order
|
||||||
|
# * Make sure each model has one field with primary_key=True
|
||||||
|
# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
|
||||||
|
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
|
||||||
|
# Feel free to rename the models, but don't rename db_table values or field names.
|
||||||
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
|
class Authors(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
link = models.TextField()
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('author-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'authors'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Comments(models.Model):
|
||||||
|
book = models.ForeignKey("Books", db_column="book", on_delete=models.CASCADE)
|
||||||
|
text = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'comments'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="comments_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Data(models.Model):
|
||||||
|
book = models.IntegerField()
|
||||||
|
format = models.TextField()
|
||||||
|
uncompressed_size = models.IntegerField()
|
||||||
|
name = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'data'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["format"], name="formats_idx"),
|
||||||
|
models.Index(fields=["book"], name="data_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Identifiers(models.Model):
|
||||||
|
book = models.IntegerField()
|
||||||
|
type = models.TextField()
|
||||||
|
val = models.TextField()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.val
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'identifiers'
|
||||||
|
|
||||||
|
|
||||||
|
class Languages(models.Model):
|
||||||
|
lang_code = models.TextField()
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('language-detail-view', args=[str(self.lang_code)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.lang_code
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'languages'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["lang_code"], name="languages_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Publishers(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
released = models.ManyToManyField(
|
||||||
|
"Books",
|
||||||
|
through='BooksPublishersLink',
|
||||||
|
through_fields=('publisher', 'book'),
|
||||||
|
related_name="released"
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('publisher-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'publishers'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["name"], name="publishers_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Ratings(models.Model):
|
||||||
|
rating = models.IntegerField(blank=True, null=True)
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('rating-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return str(self.rating)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'ratings'
|
||||||
|
|
||||||
|
|
||||||
|
class Series(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('series-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'series'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["name"], name="series_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Tags(models.Model):
|
||||||
|
name = models.TextField()
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('tag-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'tags'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["name"], name="tags_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Books(models.Model):
|
||||||
|
title = models.TextField()
|
||||||
|
sort = models.TextField(blank=True, null=True)
|
||||||
|
# This field type is a guess.
|
||||||
|
timestamp = models.TextField(blank=True, null=True)
|
||||||
|
# This field type is a guess.
|
||||||
|
pubdate = models.TextField(blank=True, null=True)
|
||||||
|
series_index = models.FloatField()
|
||||||
|
author_sort = models.TextField(blank=True, null=True)
|
||||||
|
isbn = models.TextField(blank=True, null=True)
|
||||||
|
lccn = models.TextField(blank=True, null=True)
|
||||||
|
path = models.TextField()
|
||||||
|
flags = models.IntegerField()
|
||||||
|
uuid = models.TextField(blank=True, null=True)
|
||||||
|
has_cover = models.BooleanField(blank=True, null=True)
|
||||||
|
last_modified = models.TextField() # This field type is a guess.
|
||||||
|
authors = models.ManyToManyField(
|
||||||
|
Authors,
|
||||||
|
through='BooksAuthorsLink',
|
||||||
|
through_fields=('book', 'author'))
|
||||||
|
languages = models.ManyToManyField(
|
||||||
|
Languages,
|
||||||
|
through='BooksLanguagesLink',
|
||||||
|
through_fields=('book', 'lang_code'))
|
||||||
|
publishers = models.ManyToManyField(
|
||||||
|
Publishers,
|
||||||
|
through='BooksPublishersLink',
|
||||||
|
through_fields=('book', 'publisher'))
|
||||||
|
series = models.ManyToManyField(
|
||||||
|
Series,
|
||||||
|
through='BooksSeriesLink',
|
||||||
|
through_fields=('book', 'series'))
|
||||||
|
tags = models.ManyToManyField(
|
||||||
|
Tags,
|
||||||
|
through='BooksTagsLink',
|
||||||
|
through_fields=('book', 'tag'))
|
||||||
|
ratings = models.ManyToManyField(
|
||||||
|
Ratings,
|
||||||
|
through='BooksRatingsLink',
|
||||||
|
through_fields=('book', 'rating'))
|
||||||
|
def get_absolute_url(self):
|
||||||
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
|
return reverse('book-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["sort"], name="books_idx"),
|
||||||
|
models.Index(fields=["author_sort"], name="authors_idx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class BooksAuthorsLink(models.Model):
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
author = models.ForeignKey(
|
||||||
|
Authors, db_column="author", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_authors_link'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="books_authors_link_bidx"),
|
||||||
|
models.Index(fields=["author"], name="books_authors_link_aidx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class BooksLanguagesLink(models.Model):
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
lang_code = models.ForeignKey(
|
||||||
|
Languages, db_column="lang_code", on_delete=models.CASCADE)
|
||||||
|
item_order = models.IntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_languages_link'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="books_languages_link_bidx"),
|
||||||
|
models.Index(fields=["lang_code"],
|
||||||
|
name="books_languages_link_aidx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class BooksPublishersLink(models.Model):
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
publisher = models.ForeignKey(
|
||||||
|
Publishers, db_column="publisher", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_publishers_link'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="books_publishers_link_bidx"),
|
||||||
|
models.Index(fields=["publisher"],
|
||||||
|
name="books_publishers_link_aidx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class BooksRatingsLink(models.Model): # TODO add this somehow
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
rating = models.ForeignKey(
|
||||||
|
Ratings, db_column="rating", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_ratings_link'
|
||||||
|
|
||||||
|
|
||||||
|
class BooksSeriesLink(models.Model):
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
series = models.ForeignKey(
|
||||||
|
Series, db_column="series", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_series_link'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="books_series_link_bidx"),
|
||||||
|
models.Index(fields=["series"], name="books_series_link_aidx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class BooksTagsLink(models.Model):
|
||||||
|
book = models.ForeignKey(Books, db_column="book", on_delete=models.CASCADE)
|
||||||
|
tag = models.ForeignKey(Tags, db_column="tag", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'books_tags_link'
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["book"], name="books_tags_link_bidx"),
|
||||||
|
models.Index(fields=["tag"], name="books_tags_link_aidx"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# class BooksPluginData(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
# name = models.TextField()
|
||||||
|
# val = models.TextField()
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'books_plugin_data'
|
||||||
|
|
||||||
|
|
||||||
|
# class ConversionOptions(models.Model):
|
||||||
|
# format = models.TextField()
|
||||||
|
# book = models.IntegerField(blank=True, null=True)
|
||||||
|
# data = models.BinaryField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'conversion_options'
|
||||||
|
#
|
||||||
|
# class LibraryId(models.Model):
|
||||||
|
# uuid = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'library_id'
|
||||||
|
#
|
||||||
|
# class CustomColumns(models.Model):
|
||||||
|
# label = models.TextField()
|
||||||
|
# name = models.TextField()
|
||||||
|
# datatype = models.TextField()
|
||||||
|
# mark_for_delete = models.BooleanField()
|
||||||
|
# editable = models.BooleanField()
|
||||||
|
# display = models.TextField()
|
||||||
|
# is_multiple = models.BooleanField()
|
||||||
|
# normalized = models.BooleanField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'custom_columns'
|
||||||
|
#
|
||||||
|
# class Preferences(models.Model):
|
||||||
|
# key = models.TextField()
|
||||||
|
# val = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'preferences'
|
||||||
|
#
|
||||||
|
# class Feeds(models.Model):
|
||||||
|
# title = models.TextField()
|
||||||
|
# script = models.TextField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'feeds'
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# class LastReadPositions(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
# format = models.TextField()
|
||||||
|
# user = models.TextField()
|
||||||
|
# device = models.TextField()
|
||||||
|
# cfi = models.TextField()
|
||||||
|
# epoch = models.FloatField()
|
||||||
|
# pos_frac = models.FloatField()
|
||||||
|
#
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'last_read_positions'
|
||||||
|
|
||||||
|
|
||||||
|
# class MetadataDirtied(models.Model):
|
||||||
|
# book = models.IntegerField()
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# managed = False
|
||||||
|
# db_table = 'metadata_dirtied'
|
58
CalibreWebCompanion/library/static/css/styles.css
Normal file
58
CalibreWebCompanion/library/static/css/styles.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* Fixed sidenav, full height */
|
||||||
|
.sidenav {
|
||||||
|
height: 100%;
|
||||||
|
width: 200px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #111;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the sidenav links and the dropdown button */
|
||||||
|
.sidenav a, .dropdown-btn {
|
||||||
|
padding: 6px 8px 6px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #818181;
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
width:100%;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On mouse-over */
|
||||||
|
.sidenav a:hover, .dropdown-btn:hover {
|
||||||
|
color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main content */
|
||||||
|
.main {
|
||||||
|
margin-left: 200px; /* Same as the width of the sidenav */
|
||||||
|
font-size: 20px; /* Increased text to enable scrolling */
|
||||||
|
padding: 0px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an active class to the active dropdown button */
|
||||||
|
.active {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
|
||||||
|
.dropdown-container {
|
||||||
|
display: none;
|
||||||
|
background-color: #262626;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: Style the caret down icon */
|
||||||
|
.fa-caret-down {
|
||||||
|
float: right;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
14
CalibreWebCompanion/library/static/js/nav.js
Normal file
14
CalibreWebCompanion/library/static/js/nav.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
var dropdown = document.getElementsByClassName("dropdown-btn");
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < dropdown.length; i++) {
|
||||||
|
dropdown[i].addEventListener("click", function() {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var dropdownContent = this.nextElementSibling;
|
||||||
|
if (dropdownContent.style.display === "block") {
|
||||||
|
dropdownContent.style.display = "none";
|
||||||
|
} else {
|
||||||
|
dropdownContent.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
54
CalibreWebCompanion/library/templates/base.html
Normal file
54
CalibreWebCompanion/library/templates/base.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
{% block title %}<title>Local Library</title>{% endblock %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
|
<!-- Add additional CSS in static file -->
|
||||||
|
{% load static %}
|
||||||
|
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-2">
|
||||||
|
{% block sidebar %}
|
||||||
|
<div class="sidenav">
|
||||||
|
<a href="#about">About</a>
|
||||||
|
<a href="#services">Services</a>
|
||||||
|
<a href="#clients">Clients</a>
|
||||||
|
<a href="#contact">Contact</a>
|
||||||
|
<button class="dropdown-btn">Dropdown
|
||||||
|
<i class="fa fa-caret-down"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-container">
|
||||||
|
<a href="#">Link 1</a>
|
||||||
|
<a href="#">Link 2</a>
|
||||||
|
<a href="#">Link 3</a>
|
||||||
|
</div>
|
||||||
|
<a href="#contact">{{counter}} books</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var dropdown = document.getElementsByClassName("dropdown-btn");
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < dropdown.length; i++) {
|
||||||
|
dropdown[i].addEventListener("click", function() {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var dropdownContent = this.nextElementSibling;
|
||||||
|
if (dropdownContent.style.display === "block") {
|
||||||
|
dropdownContent.style.display = "none";
|
||||||
|
} else {
|
||||||
|
dropdownContent.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,19 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>{{authors}}</h1>
|
||||||
|
{% if books %}
|
||||||
|
<ul>
|
||||||
|
{% for book in books %}
|
||||||
|
|
||||||
|
<li><a href="{{book.get_absolute_url}}">{{book.title}}</a></li>
|
||||||
|
{%endfor%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Author List</h1>
|
||||||
|
{% if authors_list %}
|
||||||
|
<ul>
|
||||||
|
{% for author in authors_list %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ author.get_absolute_url }}">{{ author.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>There are no authors in the library.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,47 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>{{books.title}} by
|
||||||
|
{% if books.authors %}
|
||||||
|
{% for author in books.authors.all %}
|
||||||
|
<a href="{{author.get_absolute_url}}">{{author.name}}</a>
|
||||||
|
{%endfor%}
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{books.author_sort}}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
Published by
|
||||||
|
{% if books.publishers %}
|
||||||
|
{% for pub in books.publishers.all %}
|
||||||
|
<a href="{{pub.get_absolute_url}}">{{pub.name}}</a>
|
||||||
|
{%endfor%}
|
||||||
|
{% else %}
|
||||||
|
Unknown
|
||||||
|
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
Tags:
|
||||||
|
{% if books.tags %}
|
||||||
|
{% for tag in books.tags.all %}
|
||||||
|
<a href="{{tag.get_absolute_url}}">{{tag.name}}</a>,
|
||||||
|
{%endfor%}
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
Rating:
|
||||||
|
{% if books.ratings %}
|
||||||
|
{% for rating in books.ratings.all %}
|
||||||
|
<a href="{{rating.get_absolute_url}}">{{rating}}</a>
|
||||||
|
{%endfor%}
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
<a href="{{book.publisher.get_absolute_url}}">{{book.publisher}}</a>
|
||||||
|
</h1>
|
||||||
|
{{comment}}
|
||||||
|
<a href="{% static "" %}{{download}}"><img src="{% static "" %}{{imgpath}}" alt="" srcset=""></a>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Book List</h1>
|
||||||
|
{% if books_list %}
|
||||||
|
<ul>
|
||||||
|
{% for book in books_list %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author_sort}})
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>There are no books in the library.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>{{authors}} </h1>
|
||||||
|
|
||||||
|
{% if publishers.released %}
|
||||||
|
<ul>
|
||||||
|
{% for book in publishers.released.all %}
|
||||||
|
|
||||||
|
<li><a href="{{book.get_absolute_url}}">{{book.title}}</a></li>
|
||||||
|
{%endfor%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Publishers List</h1>
|
||||||
|
{% if publishers_list %}
|
||||||
|
<ul>
|
||||||
|
{% for publisher in publishers_list %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ publisher.get_absolute_url }}">{{ publisher.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>There are no publishers in the library.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,20 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<h1>{{ratings}}</h1>
|
||||||
|
{% if books %}
|
||||||
|
<ul>
|
||||||
|
{% for book in books %}
|
||||||
|
|
||||||
|
<li><a href="{{book.get_absolute_url}}">{{book.title}}</a></li>
|
||||||
|
{%endfor%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Ratings List</h1>
|
||||||
|
{% if ratings_list %}
|
||||||
|
<ul>
|
||||||
|
{% for rating in ratings_list %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ rating.get_absolute_url }}">{{ rating.rating }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>There are no ratings in the library.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,20 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<h1>{{tags}}</h1>
|
||||||
|
{% if books %}
|
||||||
|
<ul>
|
||||||
|
{% for book in books %}
|
||||||
|
|
||||||
|
<li><a href="{{book.get_absolute_url}}">{{book.title}}</a></li>
|
||||||
|
{%endfor%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
17
CalibreWebCompanion/library/templates/library/tags_list.html
Normal file
17
CalibreWebCompanion/library/templates/library/tags_list.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Tags List</h1>
|
||||||
|
{% if tags_list %}
|
||||||
|
<ul>
|
||||||
|
{% for tag in tags_list %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ tag.get_absolute_url }}">{{ tag.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>There are no tags in the library.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
1
CalibreWebCompanion/library/templatetags/__init__.py
Normal file
1
CalibreWebCompanion/library/templatetags/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from . import custom
|
9
CalibreWebCompanion/library/templatetags/custom.py
Normal file
9
CalibreWebCompanion/library/templatetags/custom.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from django import template
|
||||||
|
from ..models import Books
|
||||||
|
|
||||||
|
register = template.Library
|
||||||
|
print("I ACTUALLY CAME HEReEe")
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def dummy():
|
||||||
|
return Books.objects.count()
|
3
CalibreWebCompanion/library/tests.py
Normal file
3
CalibreWebCompanion/library/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
20
CalibreWebCompanion/library/urls.py
Normal file
20
CalibreWebCompanion/library/urls.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('authors/', views.AuthorListView.as_view(), name='authors'),
|
||||||
|
path('books/', views.BookListView.as_view(), name='books'),
|
||||||
|
path('publishers/', views.PublisherListView.as_view(), name='publishers'),
|
||||||
|
path('ratings/', views.RatingListView.as_view(), name='ratings'),
|
||||||
|
path('tags/', views.TagListView.as_view(), name='tags'),
|
||||||
|
|
||||||
|
path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail-view'),
|
||||||
|
path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail-view'),
|
||||||
|
path('publisher/<int:pk>', views.PublisherDetailView.as_view(), name='publisher-detail-view'),
|
||||||
|
path('rating/<int:pk>', views.RatingDetailView.as_view(), name='rating-detail-view'),
|
||||||
|
path('tag/<int:pk>', views.TagDetailView.as_view(), name='tag-detail-view'),
|
||||||
|
|
||||||
|
|
||||||
|
]
|
81
CalibreWebCompanion/library/views.py
Normal file
81
CalibreWebCompanion/library/views.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from django.views import generic
|
||||||
|
from .models import Authors, Books, Comments, Ratings, BooksAuthorsLink, Publishers, Tags, BooksTagsLink, BooksRatingsLink, Data
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorListView(generic.ListView):
|
||||||
|
model = Authors
|
||||||
|
|
||||||
|
|
||||||
|
class BookListView(generic.ListView):
|
||||||
|
model = Books
|
||||||
|
|
||||||
|
|
||||||
|
class PublisherListView(generic.ListView):
|
||||||
|
model = Publishers
|
||||||
|
|
||||||
|
|
||||||
|
class RatingListView(generic.ListView):
|
||||||
|
model = Ratings
|
||||||
|
|
||||||
|
|
||||||
|
class TagListView(generic.ListView):
|
||||||
|
model = Tags
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorDetailView(generic.DetailView):
|
||||||
|
model = Authors
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
# Call the base implementation first to get the context
|
||||||
|
context = super(AuthorDetailView, self).get_context_data(**kwargs)
|
||||||
|
# Create any data and add it to the context
|
||||||
|
books = BooksAuthorsLink.objects.filter(author=context["object"].id)
|
||||||
|
context['books'] = context['books'] = sorted([b.book for b in books.all()], key=lambda x: x.title)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class BookDetailView(generic.DetailView):
|
||||||
|
model = Books
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
# Call the base implementation first to get the context
|
||||||
|
context = super(BookDetailView, self).get_context_data(**kwargs)
|
||||||
|
# Create any data and add it to the context
|
||||||
|
try:
|
||||||
|
context['comment'] = Comments.objects.get(
|
||||||
|
book=context["object"].id).text
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
context["imgpath"] = context["object"].path + "/cover.jpg"
|
||||||
|
download = Data.objects.get(book=context["object"].id)
|
||||||
|
context["download"] = f"{context['object'].path}/{download.name}.{download.format}"
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class PublisherDetailView(generic.DetailView):
|
||||||
|
model = Publishers
|
||||||
|
|
||||||
|
|
||||||
|
class RatingDetailView(generic.DetailView):
|
||||||
|
model = Ratings
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
# Call the base implementation first to get the context
|
||||||
|
context = super(RatingDetailView, self).get_context_data(**kwargs)
|
||||||
|
# Create any data and add it to the context
|
||||||
|
books = BooksRatingsLink.objects.filter(rating=context["object"].id)
|
||||||
|
context['books'] = sorted([b.book for b in books.all()], key=lambda x: x.title)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class TagDetailView(generic.DetailView):
|
||||||
|
model = Tags
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
# Call the base implementation first to get the context
|
||||||
|
context = super(TagDetailView, self).get_context_data(**kwargs)
|
||||||
|
# Create any data and add it to the context
|
||||||
|
books = BooksTagsLink.objects.filter(tag=context["object"].id)
|
||||||
|
context['books'] = sorted([b.book for b in books.all()], key=lambda x: x.title)
|
||||||
|
return context
|
21
CalibreWebCompanion/manage.py
Normal file
21
CalibreWebCompanion/manage.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CalibreWebCompanion.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# requirements
|
||||||
|
Django 3.0
|
||||||
|
|
||||||
|
# how to use:
|
||||||
|
Edit `./CalibreWebCompanion/CalibreWebCompanion/settings`.
|
||||||
|
Set CALIBREPATH to the path of your library
|
||||||
|
`./CalibreWebCompanion`
|
||||||
|
run `./manage.py runserver`
|
||||||
|
|
||||||
|
this is in development mode. don't actually use it or release it like this. The debug info it shows is spicy.
|
BIN
models.vsdx
Normal file
BIN
models.vsdx
Normal file
Binary file not shown.
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
django=3.0.8
|
Loading…
Reference in New Issue
Block a user