Update HTML

This commit is contained in:
Joakim Hellsén 2024-01-30 05:37:14 +01:00
commit 6f544db209
8 changed files with 137 additions and 41 deletions

View file

@ -4,6 +4,7 @@
"feedburner", "feedburner",
"feedparser", "feedparser",
"feedvault", "feedvault",
"leftright",
"PGHOST", "PGHOST",
"PGPORT", "PGPORT",
"PGUSER", "PGUSER",

View file

@ -2,7 +2,7 @@
from django.urls import path from django.urls import path
from feeds.views import FeedsView, IndexView from feeds.views import APIView, FeedsView, IndexView, add_feeds
app_name = "feeds" app_name = "feeds"
@ -11,4 +11,8 @@ urlpatterns = [
path("", IndexView.as_view(), name="index"), path("", IndexView.as_view(), name="index"),
# /feeds # /feeds
path("feeds", FeedsView.as_view(), name="feeds"), path("feeds", FeedsView.as_view(), name="feeds"),
# /add
path("add", add_feeds, name="add"),
# /api
path("api", APIView.as_view(), name="api"),
] ]

View file

@ -8,12 +8,17 @@ from __future__ import annotations
import typing import typing
from django.contrib import messages
from django.db import connection from django.db import connection
from django.shortcuts import redirect
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from feeds.models import Feed from feeds.models import Feed
if typing.TYPE_CHECKING:
from django.http import HttpRequest, HttpResponseRedirect
def get_database_size() -> int: def get_database_size() -> int:
"""Get the size of a database. """Get the size of a database.
@ -65,3 +70,45 @@ class FeedsView(ListView):
context["feed_count"] = Feed.objects.count() context["feed_count"] = Feed.objects.count()
context["database_size"] = get_database_size() context["database_size"] = get_database_size()
return context return context
def add_feeds(request: HttpRequest) -> HttpResponseRedirect:
"""Add feeds to the database.
Args:
request: The request object.
Returns:
A redirect to the index page.
"""
if request.method == "POST":
urls = request.POST.get("urls")
if not urls:
messages.error(request, "No URLs provided")
return redirect("feeds:index", permanent=False)
if urls == "Test":
messages.error(request, "Hello, world!")
return redirect("feeds:index", permanent=False)
for url in urls.splitlines():
print(f"Adding {url} to the database...") # noqa: T201
return redirect("feeds:feeds", permanent=False)
msg: str = f"You must use a POST request. You used a {request.method} request. You can find out how to use this endpoint here: <a href=''>http://127.0.0.1:8000/</a>. If you think this is a mistake, please contact the administrator." # noqa: E501
messages.error(request, msg)
return redirect("feeds:index", permanent=False)
class APIView(TemplateView):
"""Index page."""
template_name = "api.html"
def get_context_data(self: APIView, **kwargs: dict) -> dict:
"""Add feed count and database size to context data."""
context: dict = super().get_context_data(**kwargs)
context["feed_count"] = Feed.objects.count()
context["database_size"] = get_database_size()
return context

1
static/Feed.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 256 256" cursor="default"><defs><linearGradient x1=".085" y1=".085" x2=".915" y2=".915" id="prefix__a"><stop offset="0" stop-color="#E3702D"/><stop offset=".107" stop-color="#EA7D31"/><stop offset=".35" stop-color="#F69537"/><stop offset=".5" stop-color="#FB9E3A"/><stop offset=".702" stop-color="#EA7C31"/><stop offset=".887" stop-color="#DE642B"/><stop offset="1" stop-color="#D95B29"/></linearGradient></defs><rect width="256" height="256" rx="55" ry="55" fill="#CC5D15"/><rect width="246" height="246" rx="50" ry="50" x="5" y="5" fill="#F49C52"/><rect width="236" height="236" rx="47" ry="47" x="10" y="10" fill="url(#prefix__a)"/><circle cx="68" cy="189" r="24" fill="#FFF"/><path d="M160 213h-34a82 82 0 00-82-82V97a116 116 0 01116 116z" fill="#FFF"/><path d="M184 213A140 140 0 0044 73V38a175 175 0 01175 175z" fill="#FFF"/></svg>

After

Width:  |  Height:  |  Size: 916 B

View file

@ -1,25 +1,19 @@
html { html {
max-width: 70ch; max-width: 70ch;
/* larger spacing on larger screens, very small spacing on tiny screens */
padding: calc(1vmin + 0.5rem); padding: calc(1vmin + 0.5rem);
/* shorthand for margin-left/margin-right */
margin-inline: auto; margin-inline: auto;
/* fluid sizing: https://frontaid.io/blog/fluid-typography-2d-css-locks-clamp/ */
font-size: clamp(1em, 0.909em + 0.45vmin, 1.25em); font-size: clamp(1em, 0.909em + 0.45vmin, 1.25em);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif; Arial, sans-serif;
/* use dark mode if user prefers it */
color-scheme: light dark; color-scheme: light dark;
} }
/* h1 */
h1 { h1 {
font-size: 2.5rem; font-size: 2.5rem;
font-weight: 600; font-weight: 600;
margin: 0; margin: 0;
} }
/* FeedVault logo */
.title { .title {
text-align: center; text-align: center;
} }
@ -27,21 +21,15 @@ h1 {
.search { .search {
display: flex; display: flex;
justify-content: center; justify-content: center;
/* Spacing between search bar and nav bar */
margin-top: 1rem; margin-top: 1rem;
/* Center the search bar */
margin-inline: auto; margin-inline: auto;
} }
/* Links at the top and bottom of the page */
.leftright { .leftright {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
/* Align the links to the left and right */
.left { .left {
margin-right: auto; margin-right: auto;
} }
@ -50,9 +38,16 @@ h1 {
margin-left: auto; margin-left: auto;
} }
/* Add feeds box */
textarea { textarea {
width: 100%; width: 100%;
height: 10rem; height: 10rem;
resize: vertical; resize: vertical;
} }
.error {
color: red;
}
.messages {
list-style-type: none;
}

8
templates/api.html Normal file
View file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}<title>Feeds</title>{% endblock %}
{% block description %}FeedVault - A feed archive{% endblock %}
{% block keywords %}RSS, Atom, Feed, Archive{% endblock %}
{% block content %}
<h2>API documentation</h2>
<p>Here be dragons.</p>
{% endblock %}

View file

@ -13,20 +13,39 @@
{% if canonical_url %}<link rel="canonical" href="{{ canonical_url }}">{% endif %} {% if canonical_url %}<link rel="canonical" href="{{ canonical_url }}">{% endif %}
</head> </head>
<body> <body>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message|safe }}</li>
{% endfor %}
</ul>
<hr>
{% endif %}
<span class="title"> <span class="title">
<a href="{% url 'feeds:index' %}"> <h1>
<h1>FeedVault</h1> <a href="{% url 'feeds:index' %}">FeedVault</a>
</a> </h1>
</span> </span>
<small>An archive of <a href="https://en.wikipedia.org/wiki/Web_feed">web feeds</a>. Currently archiving {{ feed_count }} feeds. ~{{ database_size|floatformat:2 }} MB of data.</small> <div class="leftright">
<div class="left">
<small>Archive of <a href="https://en.wikipedia.org/wiki/Web_feed">web feeds</a>. {{ feed_count }} feeds. ~{{ database_size|floatformat:2 }} MB.</small>
</div>
<div class="right">
<!-- Search -->
<form action="#" method="get">
<input type="text" name="q" placeholder="Search">
<button type="submit">Search</button>
</form>
</div>
</div>
<nav> <nav>
<small> <small>
<div class="leftright"> <div class="leftright">
<div class="left"> <div class="left">
<a href="{% url 'feeds:feeds' %}">Feeds</a> | <a href="">About</a> | <a href="">API</a> | <a href="">Stats</a> | <a href="">GitHub</a> | <a href="">Donate</a> <a href="{% url 'feeds:feeds' %}">Feeds</a> | <a href="{% url 'feeds:api' %}">API</a> | <a href="https://github.com/TheLovinator1/FeedVault">GitHub</a> | <a href="https://github.com/sponsors/TheLovinator1">Donate</a>
</div> </div>
<div class="right"> <div class="right">
<a href="">Login</a> <a href="">Register</a> | <a href="">Login</a>
</div> </div>
</div> </div>
</small> </small>

View file

@ -15,46 +15,67 @@
<br> <br>
<br> <br>
<details> <details>
<summary>What is RSS and Atom?</summary> <summary>What are web feeds?</summary>
<p> <p>
RSS and Atom are two different formats for <a href="https://en.wikipedia.org/wiki/Web_feed">web feeds</a>. They are used to publish frequently updated content such as blog posts, news articles, etc. Web feeds are a way for you to "subscribe" to content on a website. When you subscribe to a feed, you will be notified when new content is published. You can then read the content in a feed reader.
Feeds are usually available in the RSS or Atom format. You can recognize a feed by the following icon:
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgY3Vyc29yPSJkZWZhdWx0Ij48ZGVmcz48bGluZWFyR3JhZGllbnQgeDE9Ii4wODUiIHkxPSIuMDg1IiB4Mj0iLjkxNSIgeTI9Ii45MTUiIGlkPSJwcmVmaXhfX2EiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI0UzNzAyRCIvPjxzdG9wIG9mZnNldD0iLjEwNyIgc3RvcC1jb2xvcj0iI0VBN0QzMSIvPjxzdG9wIG9mZnNldD0iLjM1IiBzdG9wLWNvbG9yPSIjRjY5NTM3Ii8+PHN0b3Agb2Zmc2V0PSIuNSIgc3RvcC1jb2xvcj0iI0ZCOUUzQSIvPjxzdG9wIG9mZnNldD0iLjcwMiIgc3RvcC1jb2xvcj0iI0VBN0MzMSIvPjxzdG9wIG9mZnNldD0iLjg4NyIgc3RvcC1jb2xvcj0iI0RFNjQyQiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0Q5NUIyOSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2IiByeD0iNTUiIHJ5PSI1NSIgZmlsbD0iI0NDNUQxNSIvPjxyZWN0IHdpZHRoPSIyNDYiIGhlaWdodD0iMjQ2IiByeD0iNTAiIHJ5PSI1MCIgeD0iNSIgeT0iNSIgZmlsbD0iI0Y0OUM1MiIvPjxyZWN0IHdpZHRoPSIyMzYiIGhlaWdodD0iMjM2IiByeD0iNDciIHJ5PSI0NyIgeD0iMTAiIHk9IjEwIiBmaWxsPSJ1cmwoI3ByZWZpeF9fYSkiLz48Y2lyY2xlIGN4PSI2OCIgY3k9IjE4OSIgcj0iMjQiIGZpbGw9IiNGRkYiLz48cGF0aCBkPSJNMTYwIDIxM2gtMzRhODIgODIgMCAwMC04Mi04MlY5N2ExMTYgMTE2IDAgMDExMTYgMTE2eiIgZmlsbD0iI0ZGRiIvPjxwYXRoIGQ9Ik0xODQgMjEzQTE0MCAxNDAgMCAwMDQ0IDczVjM4YTE3NSAxNzUgMCAwMTE3NSAxNzV6IiBmaWxsPSIjRkZGIi8+PC9zdmc+"
alt="Feed icon"
width="16"
height="16">
<br>
<br>
You can read more about web feeds on <a href="https://en.wikipedia.org/wiki/Web_feed">Wikipedia</a>.
</p>
<hr>
</details>
<details>
<summary>What is FeedVault?</summary>
<p>
FeedVault is designed to collect, organize, and store information from RSS feeds. It parses XML data using the <a href="https://github.com/kurtmckee/feedparser">feedparser by Kurt McKee</a> library and stores the relevant information in a PostgreSQL database managed by Django.
</p> </p>
<hr> <hr>
</details> </details>
<details> <details>
<summary>Why archive feeds?</summary> <summary>Why archive feeds?</summary>
<p> <p>
<h3>Preserving Content History</h3> The web is constantly changing. Websites are redesigned, content is removed, and links are broken. By archiving feeds, we can preserve the content that is published on the web.
<p>
The web is constantly changing. Websites are redesigned, articles are deleted, and content is lost. By archiving feeds, we can preserve the history of the web.
</p>
<h3>Research and Reference</h3>
<p>
Researchers, journalists, or individuals conducting studies may find value in archiving RSS feeds to create a reference library. This can aid in analyzing trends, tracking changes in information, or referencing past data for various purposes.
</p>
<h3>Long-Term Availability</h3>
<p>
Websites and feeds may change or disappear over time due to various reasons. Archiving ensures that users have a reliable and persistent source for accessing content even if the original sources are no longer available.
</p>
<h3>Content Analysis and Statistics</h3>
<p>
Archiving feeds can facilitate content analysis and statistical insights. Users may want to track the frequency of updates, analyze the popularity of certain topics, or gather data for research purposes.
</p>
</p> </p>
<hr> <hr>
</details> </details>
<details> <details>
<summary>How does it work?</summary> <summary>How does it work?</summary>
<p> <p>
FeedVault uses <a href="https://github.com/kurtmckee/feedparser">feedparser</a> to parse the feeds. The parsed feeds are then stored in a database. The feeds are updated every 30 minutes. <ul>
<li>
Parse XML data using the <a href="https://github.com/kurtmckee/feedparser">feedparser</a> library.
</li>
<li>
Before saving the parsed data to the database, HTML content is <a href="https://feedparser.readthedocs.io/en/latest/html-sanitization.html">sanitized</a>.
</li>
<li>The sanitized data is then stored in a PostgreSQL database using Django's ORM.</li>
<li>
The data is then made available through the website and the <a href="/api">API</a>.
</li>
</ul>
</p> </p>
<hr> <hr>
</details> </details>
<details> <details>
<summary>How can I access the archived feeds?</summary> <summary>How can I access the archived feeds?</summary>
<p> <p>
You can find feeds by using the search bar at the top of the page. You can also use the <a href="/api">API</a> to access the feeds. <ul>
<li>You can search for feeds through the search bar at the top of the page.</li>
<li>
You can access the archived feeds through the <a href="/feeds">website</a>.
</li>
<li>
You can access the archived feeds through the <a href="/api">API</a>.
</li>
<li>
You can download database dumps from <a href="">here</a>.
</li>
</ul>
</p> </p>
<hr>
</details> </details>
{% endblock %} {% endblock %}