6 Commits

Author SHA1 Message Date
TheOnlyWayUp a84d4edb6b fix(docker): Install libraries for weasyprint 2025-11-10 00:29:38 +05:30
TheOnlyWayUp 1379f416bc fix(docker): .dockerignore targets subdirectories 2025-11-10 00:29:09 +05:30
TheOnlyWayUp 83466ded4d fix(docker): Remove cache files after install 2025-11-10 00:05:09 +05:30
Aron BenDaniel 6c1a145577 docker: Fix .dockerignore uv.lock entry 2025-10-31 05:49:08 +05:30
Dhanush R cc9ac6093f feat(api): Remove dependency on exiftool (#82) 2025-10-30 16:11:16 +05:30
Aaron BenDaniel fa60de79fd Update README.md copyright year
The future is now.
2025-10-29 01:44:54 +05:30
5 changed files with 56 additions and 87 deletions
+11 -10
View File
@@ -1,10 +1,11 @@
__pycache__
*ipynb
build
.idea
.vscode
.venv
.env
*log
*.md
uv.lock
**/__pycache__/
**/*.ipynb
**/build/
.idea/
.vscode/
**/.venv/
**/.env
**/.env_template
**/*.log
**/*.md
src/api/uv.lock
+6 -16
View File
@@ -1,4 +1,4 @@
FROM node:20
FROM node:20-alpine
WORKDIR /build
COPY src/frontend/package*.json .
@@ -6,10 +6,6 @@ RUN rm -rf node_modules
RUN rm -rf build
RUN npm install
COPY src/frontend/. .
ARG pdfs=false
ENV VITE_ENABLE_PDFS=$pdfs
RUN npm run build
# Thanks https://stackoverflow.com/q/76988450
@@ -17,15 +13,12 @@ FROM python:3.13-slim
WORKDIR /app
COPY --from=nobodyxu/apt-fast:latest-debian-buster-slim /usr/local/ /usr/local/
RUN apt update
RUN apt install -y aria2
RUN apt-fast install -y git build-essential python3.13-dev libgobject-2.0 libpango-1.0 libpangoft2-1.0
RUN apt update && \
apt install -y git build-essential python3.13-dev libglib2.0-0 libpango-1.0-0 libpangoft2-1.0-0 && \
apt clean && \
rm -rf /var/lib/apt/lists/*
# aiohttp-client-cache depends on multipart, which requires python3.13-dev to build successfully on 3.13
# weasyprint depends on libgoject, libpango, and libpangoft2
RUN rm -rf /var/lib/apt/lists/*
# https://github.com/TheOnlyWayUp/WattpadDownloader/pull/82#discussion_r2470358950
@@ -36,7 +29,7 @@ WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY src/api/pyproject.toml /app
RUN uv sync
RUN uv sync && uv cache clean
COPY src/api/ /app
COPY --from=0 /build/build /app/src/build
@@ -44,9 +37,6 @@ RUN ln -s /app/src/pdf/fonts /tmp/fonts
WORKDIR /app/src
ARG pdfs=false
ENV VITE_ENABLE_PDFS=$pdfs
EXPOSE 80
CMD [ "uv", "run", "main.py"]
+1 -1
View File
@@ -53,5 +53,5 @@ My thanks to [aerkalov/ebooklib](https://github.com/aerkalov/ebooklib) for a fas
---
<div align="center">
<p>TheOnlyWayUp © 2024</p>
<p>TheOnlyWayUp © 2025</p>
</div>
+1 -11
View File
@@ -2,7 +2,6 @@
import asyncio
from enum import Enum
from os import getenv
from pathlib import Path
from typing import Optional
from zipfile import ZipFile
@@ -37,8 +36,6 @@ from create_book.parser import clean_tree, fetch_tree_images
app = FastAPI()
BUILD_PATH = Path(__file__).parent / "build"
PDFS_ENABLED = True if getenv("VITE_ENABLE_PDFS") == "true" else False
class RequestCancelledMiddleware:
# Thanks https://github.com/fastapi/fastapi/discussions/11360#discussion-6427734
@@ -161,13 +158,6 @@ async def handle_download(
else:
cookies = None
if format == DownloadFormat.pdf and not PDFS_ENABLED:
logger.error("PDF Downloads not enabled.")
return HTMLResponse(
status_code=403,
content='PDF Downloads have been disabled by the server administrator. Support is available on the <a href="https://discord.gg/P9RHC4KCwd" target="_blank">Discord</a>',
)
match mode:
case DownloadMode.story:
story_id = download_id
@@ -225,7 +215,7 @@ async def handle_download(
yield chunk
return StreamingResponse(
book_buffer if PDFS_ENABLED else iterfile(),
iterfile(),
media_type=media_type,
headers={
"Content-Disposition": f'attachment; filename="{slugify(metadata["title"])}_{story_id}{"_images" if download_images else ""}.{format.value}"', # Thanks https://stackoverflow.com/a/72729058
+37 -49
View File
@@ -1,6 +1,4 @@
<script>
const PDFS_ENABLED = import.meta.env.VITE_ENABLE_PDFS === "true";
let downloadImages = $state(false);
let downloadAsPdf = $state(false); // 0 = epub, 1 = pdf
let isPaidStory = $state(false);
@@ -112,32 +110,29 @@
>
WP Downloader
</h1>
{#if !PDFS_ENABLED}
<div role="alert" class="alert mt-10 max-w-md break-words bg-green-200">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-current"
<div role="alert" class="alert mt-10 max-w-md break-words bg-green-200">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-current"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<div>
<p>
Donators get access to <span class="font-semibold">high-speed PDF Downloads</span>
</p>
<a href="https://buymeacoffee.com/theonlywayup" class="link" target="_blank"
>Donate now</a
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<div>
<p>
Donators get access to <span class="font-semibold">high-speed PDF Downloads</span>
</p>
<a href="https://buymeacoffee.com/theonlywayup" class="link" target="_blank"
>Donate now</a
>
</div>
</div>
{/if}
</div>
<!-- <div role="alert" class="alert bg-cyan-300 mt-5">
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -159,13 +154,10 @@
</p>
<ul class="list list-inside pt-4 text-xl">
<!-- TODO: 'max-lg: hidden' to hide on screen sizes smaller than lg. I'll do this when I figure out how to make this show up _below_ the card on smaller screen sizes. -->
<!-- <li>12/24 - ⚡ Super-fast Downloads!</li>
<li>12/24 - 📑 PDF Downloads!</li> -->
<li>05/25 - ⚖️ Legal Compliance</li>
{#if PDFS_ENABLED}
<li>12/24 - ⚡ Super-fast Downloads!</li>
<li>12/24 - 📑 PDF Downloads!</li>
{:else}
<li>12/24 - 📂 Less Errors, Throttled Downloads</li>
{/if}
<li>12/24 - 📂 Less Errors, Throttled Downloads</li>
<li>11/24 - 🔗 Paste Links!</li>
<li>11/24 - 📨 Send to Kindle Support!</li>
@@ -257,30 +249,26 @@
href={url}
onclick={() => (afterDownloadPage = true)}>Download</a
>
</div>
{#if PDFS_ENABLED}
<label class="swap w-fit label mt-2 pb-2">
<!-- <label class="swap w-fit label mt-2">
<input type="checkbox" bind:checked={downloadAsPdf} />
<div class="swap-on absolute left-0 text-gray-800">
<div class="swap-on">
Downloading as <span class=" underline text-bold">PDF</span> (Click)
</div>
<div class="swap-off absolute left-0 text-gray-800">
<div class="swap-off">
Downloading as <span class=" underline text-bold">EPUB</span> (Click)
</div>
</label>
{/if}
</label> -->
<label class="label cursor-pointer">
<span class="label-text text-gray-800"
>Include Images (<strong>Slower Download</strong>)</span
>
<input
type="checkbox"
class="checkbox-warning checkbox shadow-md"
bind:checked={downloadImages}
/>
</label>
<label class="label cursor-pointer">
<span class="label-text text-gray-800">Include Images (<strong>Slower Download</strong>)</span>
<input
type="checkbox"
class="checkbox-warning checkbox shadow-md"
bind:checked={downloadImages}
/>
</label>
</div>
</form>
</div>
{:else}