Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PDF generation feature #29

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,17 @@ These steps will set up and run your local Freedium instance.
- [ ] Integrate Grafana/Prometheus to monitor our services
- [ ] Add more metrics to our services to have ability to monitor it
- [ ] Make able translate posts to different languages using translatepy library

## New PDF Generation Feature

We have added a new feature that allows you to save Medium articles as PDFs. Here are the steps to use this feature:

1. Navigate to the article you want to save as a PDF.
2. Click on the "Save as PDF" button.
3. The article will be downloaded as a PDF file.

This feature is powered by the WeasyPrint library, which converts HTML content to PDF format. The implementation details can be found in the following files:

- `web/server/handlers/post.py`: Contains the endpoint for PDF generation.
- `web/server/templates/post.html`: Ensures compatibility with PDF rendering.
- `new-web/src/routes/[slug]/+page.svelte`: Adds the "Save as PDF" button and implements the function to call the PDF generation endpoint.
18 changes: 18 additions & 0 deletions new-web/src/routes/[slug]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ Stay tuned for more exciting updates as we continue to revolutionize the world o
contentLoaded = true;
}, 500);
});

async function saveAsPDF() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nahhh, this should be definetly refactored

const response = await fetch(`/generate-pdf?path=${encodeURIComponent(window.location.pathname)}`);
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${data.title}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
}
</script>

<svelte:head>
Expand Down Expand Up @@ -118,6 +131,11 @@ Stay tuned for more exciting updates as we continue to revolutionize the world o
{/if}
</div>
</div>
<div class="p-6">
<button on:click={saveAsPDF} class="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600">
Save as PDF
</button>
</div>
</article>

<aside class="order-first mt-7 lg:mt-0 lg:min-w-80 lg:order-none">
Expand Down
15 changes: 12 additions & 3 deletions web/server/handlers/post.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import asyncio
import pickle

from fastapi.responses import HTMLResponse
from fastapi.responses import HTMLResponse, Response
from html5lib import serialize
from html5lib.html5parser import parse
from async_lru import alru_cache
from loguru import logger
from medium_parser import medium_parser_exceptions
from weasyprint import HTML
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add weasyprint as a dependency


from server import config, medium_cache, redis_storage, medium_parser
from server.services.jinja import base_template, homepage_template
Expand Down Expand Up @@ -47,7 +47,7 @@ async def fetch_post_metadata(post_id):
return HTMLResponse(homepage_template_rendered)


async def render_medium_post_link(path: str, use_cache: bool = True, use_redis: bool = True):
async def render_medium_post_link(path: str, use_cache: bool = True, use_redis: bool = True, as_pdf: bool = False):
redis_available = await safe_check_redis_connection(redis_storage)
logger.debug(f"Redis available: {redis_available}")

Expand Down Expand Up @@ -100,4 +100,13 @@ async def render_medium_post_link(path: str, use_cache: bool = True, use_redis:
serialized_rendered_post = serialize(parsed_rendered_post, encoding="utf-8")

send_message(f"✅ Successfully rendered post: {path}", True, "GOOD")

if as_pdf:
pdf = HTML(string=serialized_rendered_post).write_pdf()
return Response(pdf, media_type='application/pdf', headers={'Content-Disposition': f'attachment; filename="{post_id}.pdf"'})

return HTMLResponse(serialized_rendered_post)


async def generate_pdf(path: str):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see endpoint registration

return await render_medium_post_link(path, as_pdf=True)
7 changes: 7 additions & 0 deletions web/server/templates/post.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,10 @@ <h1 class="font-bold font-sans break-normal text-gray-900 dark:text-gray-100 pt-
cursor: pointer;
}
</style>
<div id="pdf-content" style="display: none;">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't understand what is this

<h1>{{ title }}</h1>
{% if subtitle %}<h2>{{ subtitle }}</h2>{% endif %}
<div>
{% for paragraph in content %}{{ paragraph }}{% endfor %}
</div>
</div>