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