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__ **/__pycache__/
*ipynb **/*.ipynb
build **/build/
.idea .idea/
.vscode .vscode/
.venv **/.venv/
.env **/.env
*log **/.env_template
*.md **/*.log
uv.lock **/*.md
src/api/uv.lock
+6 -16
View File
@@ -1,4 +1,4 @@
FROM node:20 FROM node:20-alpine
WORKDIR /build WORKDIR /build
COPY src/frontend/package*.json . COPY src/frontend/package*.json .
@@ -6,10 +6,6 @@ RUN rm -rf node_modules
RUN rm -rf build RUN rm -rf build
RUN npm install RUN npm install
COPY src/frontend/. . COPY src/frontend/. .
ARG pdfs=false
ENV VITE_ENABLE_PDFS=$pdfs
RUN npm run build RUN npm run build
# Thanks https://stackoverflow.com/q/76988450 # Thanks https://stackoverflow.com/q/76988450
@@ -17,15 +13,12 @@ FROM python:3.13-slim
WORKDIR /app WORKDIR /app
COPY --from=nobodyxu/apt-fast:latest-debian-buster-slim /usr/local/ /usr/local/ RUN apt update && \
apt install -y git build-essential python3.13-dev libglib2.0-0 libpango-1.0-0 libpangoft2-1.0-0 && \
RUN apt update apt clean && \
RUN apt install -y aria2 rm -rf /var/lib/apt/lists/*
RUN apt-fast install -y git build-essential python3.13-dev libgobject-2.0 libpango-1.0 libpangoft2-1.0
# aiohttp-client-cache depends on multipart, which requires python3.13-dev to build successfully on 3.13 # aiohttp-client-cache depends on multipart, which requires python3.13-dev to build successfully on 3.13
# weasyprint depends on libgoject, libpango, and libpangoft2 # weasyprint depends on libgoject, libpango, and libpangoft2
RUN rm -rf /var/lib/apt/lists/*
# https://github.com/TheOnlyWayUp/WattpadDownloader/pull/82#discussion_r2470358950 # 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 --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY src/api/pyproject.toml /app COPY src/api/pyproject.toml /app
RUN uv sync RUN uv sync && uv cache clean
COPY src/api/ /app COPY src/api/ /app
COPY --from=0 /build/build /app/src/build COPY --from=0 /build/build /app/src/build
@@ -44,9 +37,6 @@ RUN ln -s /app/src/pdf/fonts /tmp/fonts
WORKDIR /app/src WORKDIR /app/src
ARG pdfs=false
ENV VITE_ENABLE_PDFS=$pdfs
EXPOSE 80 EXPOSE 80
CMD [ "uv", "run", "main.py"] 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"> <div align="center">
<p>TheOnlyWayUp © 2024</p> <p>TheOnlyWayUp © 2025</p>
</div> </div>
+1 -11
View File
@@ -2,7 +2,6 @@
import asyncio import asyncio
from enum import Enum from enum import Enum
from os import getenv
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from zipfile import ZipFile from zipfile import ZipFile
@@ -37,8 +36,6 @@ from create_book.parser import clean_tree, fetch_tree_images
app = FastAPI() app = FastAPI()
BUILD_PATH = Path(__file__).parent / "build" BUILD_PATH = Path(__file__).parent / "build"
PDFS_ENABLED = True if getenv("VITE_ENABLE_PDFS") == "true" else False
class RequestCancelledMiddleware: class RequestCancelledMiddleware:
# Thanks https://github.com/fastapi/fastapi/discussions/11360#discussion-6427734 # Thanks https://github.com/fastapi/fastapi/discussions/11360#discussion-6427734
@@ -161,13 +158,6 @@ async def handle_download(
else: else:
cookies = None 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: match mode:
case DownloadMode.story: case DownloadMode.story:
story_id = download_id story_id = download_id
@@ -225,7 +215,7 @@ async def handle_download(
yield chunk yield chunk
return StreamingResponse( return StreamingResponse(
book_buffer if PDFS_ENABLED else iterfile(), iterfile(),
media_type=media_type, media_type=media_type,
headers={ headers={
"Content-Disposition": f'attachment; filename="{slugify(metadata["title"])}_{story_id}{"_images" if download_images else ""}.{format.value}"', # Thanks https://stackoverflow.com/a/72729058 "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> <script>
const PDFS_ENABLED = import.meta.env.VITE_ENABLE_PDFS === "true";
let downloadImages = $state(false); let downloadImages = $state(false);
let downloadAsPdf = $state(false); // 0 = epub, 1 = pdf let downloadAsPdf = $state(false); // 0 = epub, 1 = pdf
let isPaidStory = $state(false); let isPaidStory = $state(false);
@@ -112,32 +110,29 @@
> >
WP Downloader WP Downloader
</h1> </h1>
{#if !PDFS_ENABLED} <div role="alert" class="alert mt-10 max-w-md break-words bg-green-200">
<div role="alert" class="alert mt-10 max-w-md break-words bg-green-200"> <svg
<svg xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" fill="none"
fill="none" viewBox="0 0 24 24"
viewBox="0 0 24 24" class="h-6 w-6 shrink-0 stroke-current"
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> </div>
{/if} </div>
<!-- <div role="alert" class="alert bg-cyan-300 mt-5"> <!-- <div role="alert" class="alert bg-cyan-300 mt-5">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -159,13 +154,10 @@
</p> </p>
<ul class="list list-inside pt-4 text-xl"> <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. --> <!-- 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> <li>05/25 - ⚖️ Legal Compliance</li>
{#if PDFS_ENABLED} <li>12/24 - 📂 Less Errors, Throttled Downloads</li>
<li>12/24 - ⚡ Super-fast Downloads!</li>
<li>12/24 - 📑 PDF Downloads!</li>
{:else}
<li>12/24 - 📂 Less Errors, Throttled Downloads</li>
{/if}
<li>11/24 - 🔗 Paste Links!</li> <li>11/24 - 🔗 Paste Links!</li>
<li>11/24 - 📨 Send to Kindle Support!</li> <li>11/24 - 📨 Send to Kindle Support!</li>
@@ -257,30 +249,26 @@
href={url} href={url}
onclick={() => (afterDownloadPage = true)}>Download</a onclick={() => (afterDownloadPage = true)}>Download</a
> >
</div>
{#if PDFS_ENABLED} <!-- <label class="swap w-fit label mt-2">
<label class="swap w-fit label mt-2 pb-2">
<input type="checkbox" bind:checked={downloadAsPdf} /> <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) Downloading as <span class=" underline text-bold">PDF</span> (Click)
</div> </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) Downloading as <span class=" underline text-bold">EPUB</span> (Click)
</div> </div>
</label> </label> -->
{/if}
<label class="label cursor-pointer"> <label class="label cursor-pointer">
<span class="label-text text-gray-800" <span class="label-text text-gray-800">Include Images (<strong>Slower Download</strong>)</span>
>Include Images (<strong>Slower Download</strong>)</span <input
> type="checkbox"
<input class="checkbox-warning checkbox shadow-md"
type="checkbox" bind:checked={downloadImages}
class="checkbox-warning checkbox shadow-md" />
bind:checked={downloadImages} </label>
/> </div>
</label>
</form> </form>
</div> </div>
{:else} {:else}