Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ef95d69b | ||
|
|
c728f65e73 | ||
|
|
c1f813d70c | ||
|
|
aa66c06f88 | ||
|
|
518a8a1744 | ||
|
|
b65d878981 | ||
|
|
3d10081846 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -372,3 +372,4 @@ pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python,django,visualstudiocode,intellij+all
|
||||
|
||||
staticfiles/
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# epub2go-web
|
||||
A simple Website to provide a `NNI (Non-Nerd Interface)` to [epub2go.py](https://github.com/eneller/epub2go.py), a web to epub converter.
|
||||
|
||||
## Development
|
||||
This project uses [watchman](https://facebook.github.io/watchman/) for file watching and reloading.
|
||||
Follow the [official instructions](https://facebook.github.io/watchman/docs/install.html) for your system to install, django will default to its standard watcher otherwise.
|
||||
@@ -8,6 +8,8 @@ dependencies = [
|
||||
"celery>=5.4.0",
|
||||
"django>=5.1.6",
|
||||
"epub2go",
|
||||
"python-dotenv>=1.0.1",
|
||||
"pywatchman>=2.0.0",
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
|
||||
4
src/.watchmanconfig
Normal file
4
src/.watchmanconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"ignore_dirs": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpRequest, HttpResponse, FileResponse
|
||||
from django.http import HttpRequest, HttpResponse, FileResponse, HttpResponseBadRequest
|
||||
from django.conf import settings
|
||||
from celery import shared_task
|
||||
|
||||
@@ -12,7 +12,7 @@ import logging
|
||||
logger = logging.getLogger(__name__) #TODO configure logging
|
||||
|
||||
converter = GBConvert(downloaddir=settings.MEDIA_ROOT)
|
||||
books = get_all_books()# TODO get from pickle
|
||||
books = sorted(get_all_books(), key= lambda b: b.title)# TODO get from pickle
|
||||
gbnetloc = urlparse(allbooks_url).netloc
|
||||
|
||||
def index(request: HttpRequest):
|
||||
@@ -21,10 +21,13 @@ def index(request: HttpRequest):
|
||||
'http_host': request.META['HTTP_HOST'],
|
||||
'books': books,
|
||||
'book_count': len(books),
|
||||
'allbooks_url': allbooks_url,
|
||||
}
|
||||
|
||||
targetParam = request.GET.get('t', None)
|
||||
if targetParam:
|
||||
if validateUrl(targetParam):
|
||||
# download file
|
||||
fpath = getEpub(targetParam)
|
||||
fname = os.path.basename(fpath)
|
||||
file = open(fpath, 'rb')
|
||||
@@ -32,11 +35,12 @@ def index(request: HttpRequest):
|
||||
response['Content-Type'] = 'application/octet-stream'
|
||||
response['Content-Disposition'] = f'attachment; filename="{fname}"'
|
||||
return response
|
||||
|
||||
else: return HttpResponseBadRequest('Input URL invalid.')
|
||||
else:
|
||||
# return base view
|
||||
return render(request, 'index.html', context)
|
||||
|
||||
def validateUrl(param)->bool :
|
||||
if not param: return False
|
||||
|
||||
netloc = urlparse(param).netloc
|
||||
if(netloc == gbnetloc): return True
|
||||
|
||||
@@ -26,7 +26,7 @@ SECRET_KEY = "django-insecure-^@m5bl*8x+=@c^b0lhkgb-%_#9#&oad=v15jq=!0$g#x17zjf8
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
@@ -123,6 +123,7 @@ STATIC_URL = "static/"
|
||||
STATICFILES_DIRS = [
|
||||
PROJ_DIR / "static/",
|
||||
]
|
||||
STATIC_ROOT = PROJ_DIR/ "staticfiles"
|
||||
|
||||
MEDIA_URL = "media/"
|
||||
MEDIA_ROOT = PROJ_DIR / "media/"
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const table = document.getElementById('table');
|
||||
const table_r = Array.from(table.getElementsByTagName('tr'));
|
||||
const table_r = Array.from(table.getElementsByClassName('table-entry'));
|
||||
|
||||
// allow search from url parameter
|
||||
document.addEventListener('keydown', (event)=>{
|
||||
if (event.ctrlKey && event.key === 'k'){
|
||||
event.preventDefault();
|
||||
searchInput.select();
|
||||
}
|
||||
});
|
||||
// search from url parameter
|
||||
let searchParam = params.get('s');
|
||||
if (searchParam){
|
||||
searchInput.value = searchParam;
|
||||
console.log(searchParam);
|
||||
search(searchParam);
|
||||
}
|
||||
|
||||
@@ -16,9 +23,10 @@ function submitSearch(event){
|
||||
search();
|
||||
}
|
||||
function search(searchStr = searchInput.value){
|
||||
searchStr= searchStr.toLowerCase();
|
||||
function showMatch(tr){
|
||||
// match search with list
|
||||
let searchSuccess = Array.from(tr.getElementsByClassName('table-data')).map(e => e.textContent)
|
||||
let searchSuccess = Array.from(tr.getElementsByClassName('table-data')).map(e => e.textContent.toLowerCase())
|
||||
.join(' ')
|
||||
.indexOf(searchStr) > -1;
|
||||
if (searchSuccess) tr.style.display = "";
|
||||
|
||||
@@ -1,57 +1,78 @@
|
||||
/* this is part of the http://bettermotherfuckingwebsite.com/ */
|
||||
/*TODO also style svg icons accordingly */
|
||||
:root{
|
||||
--bg:#faf0e673;
|
||||
--bg-acc:#EEEEEE;
|
||||
--bg-hover: #DDDDDD;
|
||||
--fg:#444;
|
||||
--fg-deemph: #777;
|
||||
}
|
||||
html{
|
||||
font-family: serif;
|
||||
}
|
||||
body{
|
||||
background-color: var(--bg);
|
||||
margin:40px auto;
|
||||
max-width:650px;
|
||||
line-height:1.6;
|
||||
max-width:800px;
|
||||
line-height:1.4;
|
||||
font-size:18px;
|
||||
color:#444;
|
||||
padding:0
|
||||
10px}
|
||||
color:var(--fg);
|
||||
padding:0 10px;
|
||||
}
|
||||
|
||||
h1,h2,h3{
|
||||
line-height:1.2
|
||||
}
|
||||
|
||||
/* custom styles here */
|
||||
:root{
|
||||
--white:#faf0e673;
|
||||
}
|
||||
body{
|
||||
background-color: var(--white)
|
||||
line-height:1.2;
|
||||
letter-spacing: -2%;
|
||||
}
|
||||
header{
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 4%;
|
||||
}
|
||||
small{
|
||||
color: #777;
|
||||
color: var(--fg-deemph);
|
||||
}
|
||||
.searchbar{
|
||||
width: fit-content;
|
||||
width: 100%;
|
||||
}
|
||||
#searchInput {
|
||||
background-color: var(--bg);
|
||||
width: 100%;
|
||||
padding: .2em;
|
||||
font-size: larger;
|
||||
border-radius: 10px;
|
||||
border-color: var(--bg-acc);
|
||||
box-shadow: var(--bg-acc) 2px 2px;
|
||||
}
|
||||
table, tr{
|
||||
/* make table not resize when elements are hidden by searching */
|
||||
width: 100%;
|
||||
}
|
||||
th{
|
||||
text-align: left;
|
||||
}
|
||||
tr:nth-child(even){
|
||||
background-color: #EEEEEE;
|
||||
background-color: var(--bg-acc);
|
||||
}
|
||||
tr:hover{
|
||||
background-color: #DDDDDD;
|
||||
background-color: var(--bg-hover);
|
||||
transition: all 2ms;
|
||||
}
|
||||
.inline-icon{
|
||||
.inline-icon, .header-icon{
|
||||
vertical-align: middle;
|
||||
height: 1em;
|
||||
}
|
||||
.header-icon{
|
||||
vertical-align: middle;
|
||||
height: 1em;
|
||||
padding: .5em;
|
||||
fill: var(--fg-deemph);
|
||||
}
|
||||
a:hover, a:any-link{
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.table-link{
|
||||
/* TODO fix links with no title/content being almost unclickable */
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
@@ -11,18 +11,20 @@
|
||||
<header>
|
||||
<div>
|
||||
<h1>{{ title }}</h1>
|
||||
<a href="javascript:void(window.open('http://{{ http_host }}/?t=' + encodeURIComponent(window.location.toString())))" title="Als Lesezeichen speichern"><!--TODO fix domain part as variable-->
|
||||
<img src="{% static 'bookmark.svg' %}" alt="Bookmarklet" class="header-icon">
|
||||
</a>
|
||||
<a href="https://github.com/eneller/epub2go-web">
|
||||
<img src="{% static 'github.svg' %}" alt="GitHub" class="header-icon">
|
||||
</a></div>
|
||||
<h2>1 Click Download für Literatur</h2>
|
||||
</div>
|
||||
<search>
|
||||
<form onsubmit="submitSearch(event)" class="searchbar">
|
||||
<input type="search" id="searchInput" placeholder="Suche nach Titel" minlength="3">
|
||||
</form>
|
||||
</search>
|
||||
<small>Im Moment finden sich hier {{ book_count }} Bücher. </small>
|
||||
<small>Im Moment finden sich hier <a href="{{ allbooks_url }}">{{ book_count }} Bücher.</a> </small>
|
||||
<a href="javascript:void(window.open('http://{{ http_host }}/?t=' + encodeURIComponent(window.location.toString())))" title="Als Lesezeichen speichern"><!--TODO fix domain part as variable-->
|
||||
<img src="{% static 'bookmark.svg' %}" alt="Bookmarklet" class="header-icon">
|
||||
</a>
|
||||
<a href="https://github.com/eneller/epub2go-web">
|
||||
<img src="{% static 'github.svg' %}" alt="GitHub" class="header-icon">
|
||||
</a>
|
||||
</header>
|
||||
<main>
|
||||
<!-- NOTE use dl here?-->
|
||||
@@ -30,13 +32,13 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Title</th>
|
||||
<th>Author</th>
|
||||
<th>Titel</th>
|
||||
<th>Autor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in books %}
|
||||
<tr>
|
||||
<tr class="table-entry">
|
||||
<td>
|
||||
<a href= {{ item.url }} target="_blank" rel="noopener noreferrer" class="table-link">
|
||||
<img src="{% static 'open-link.svg' %}" alt="Open Link" class="inline-icon">
|
||||
|
||||
22
uv.lock
generated
22
uv.lock
generated
@@ -201,6 +201,8 @@ dependencies = [
|
||||
{ name = "celery" },
|
||||
{ name = "django" },
|
||||
{ name = "epub2go" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "pywatchman" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
@@ -208,6 +210,8 @@ requires-dist = [
|
||||
{ name = "celery", specifier = ">=5.4.0" },
|
||||
{ name = "django", specifier = ">=5.1.6" },
|
||||
{ name = "epub2go", git = "https://github.com/eneller/epub2go.py" },
|
||||
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
||||
{ name = "pywatchman", specifier = ">=2.0.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -266,6 +270,24 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywatchman"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cf/39/fc10dd952ac72a3a293936cd66a4551fdeb9012d2db99234a376100641ce/pywatchman-2.0.0.tar.gz", hash = "sha256:25354d9e3647f94411a4c13e510c83a1ceecc17977b0525ba41b16e7019c7b0c", size = 40570 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/51/7f/5d68d803489770cffa5d2b44be99b978c866f8a4d8e835f9da850415ed8a/pywatchman-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:51c2b4c72bea6b9fd90caf20759f5bc47febf0fd27bf2f247b87c66e2f6bab02", size = 52557 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.32.3"
|
||||
|
||||
Reference in New Issue
Block a user