feat: Control features with build arg

This commit is contained in:
AaronBenDaniel
2025-06-24 12:59:31 -04:00
committed by TheOnlyWayUp
parent b9ec2b1b5a
commit c2104ee514
3 changed files with 66 additions and 38 deletions
+7
View File
@@ -6,6 +6,10 @@ 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 feature_flag=false
ENV VITE_FEATURE_FLAG=$feature_flag
RUN npm run build RUN npm run build
# Thanks https://stackoverflow.com/q/76988450 # Thanks https://stackoverflow.com/q/76988450
@@ -40,6 +44,9 @@ RUN ln -s /app/src/pdf/fonts /tmp/fonts
WORKDIR /app/src WORKDIR /app/src
ARG feature_flag=false
ENV VITE_FEATURE_FLAG=$feature_flag
EXPOSE 80 EXPOSE 80
CMD [ "uv", "run", "main.py"] CMD [ "uv", "run", "main.py"]
+10 -1
View File
@@ -17,6 +17,7 @@ from fastapi.responses import (
StreamingResponse, StreamingResponse,
) )
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from os import getenv
from create_book import ( from create_book import (
EPUBGenerator, EPUBGenerator,
@@ -36,6 +37,8 @@ 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"
feature_flag = True if getenv("VITE_FEATURE_FLAG") == "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
@@ -192,6 +195,12 @@ async def handle_download(
book = EPUBGenerator(metadata, part_trees, cover_data, images) book = EPUBGenerator(metadata, part_trees, cover_data, images)
media_type = "application/epub+zip" media_type = "application/epub+zip"
case DownloadFormat.pdf: case DownloadFormat.pdf:
if not feature_flag:
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>',
)
author_image = await fetch_image( author_image = await fetch_image(
metadata["user"]["avatar"].replace("-256-", "-512-") metadata["user"]["avatar"].replace("-256-", "-512-")
) )
@@ -215,7 +224,7 @@ async def handle_download(
yield chunk yield chunk
return StreamingResponse( return StreamingResponse(
iterfile(), book_buffer if feature_flag else 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
+49 -37
View File
@@ -1,4 +1,6 @@
<script> <script>
const featureFlag = import.meta.env.VITE_FEATURE_FLAG === "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);
@@ -110,29 +112,32 @@
> >
WP Downloader WP Downloader
</h1> </h1>
<div role="alert" class="alert mt-10 max-w-md break-words bg-green-200"> {#if !featureFlag}
<svg <div role="alert" class="alert mt-10 max-w-md break-words bg-green-200">
xmlns="http://www.w3.org/2000/svg" <svg
fill="none" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="none"
class="h-6 w-6 shrink-0 stroke-current" 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> </div>
</div> {/if}
<!-- <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"
@@ -154,10 +159,13 @@
</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>
<li>12/24 - 📂 Less Errors, Throttled Downloads</li> {#if featureFlag}
<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>
@@ -249,26 +257,30 @@
href={url} href={url}
onclick={() => (afterDownloadPage = true)}>Download</a onclick={() => (afterDownloadPage = true)}>Download</a
> >
</div>
<!-- <label class="swap w-fit label mt-2"> {#if featureFlag}
<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"> <div class="swap-on absolute left-0 text-gray-800">
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"> <div class="swap-off absolute left-0 text-gray-800">
Downloading as <span class=" underline text-bold">EPUB</span> (Click) Downloading as <span class=" underline text-bold">EPUB</span> (Click)
</div> </div>
</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>
</div> {/if}
<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>
</form> </form>
</div> </div>
{:else} {:else}