Browse Source

JSON responses, latest + today + past requests work, web interface is pink, header image added

master
manetta 3 years ago
parent
commit
c59d206bed
  1. 121
      feedtools.py
  2. 31
      start.py
  3. 38
      static/css/stylesheet.css
  4. 81
      static/img/multifeeder.svg
  5. 45
      templates/index.html

121
feedtools.py

@ -3,80 +3,99 @@ from simpledatabase import SimpleDatabase
import json
from datetime import date, timedelta
def load():
""" Load all feeds """
def update():
""" Update all feeds """
feeds = open('feeds.txt').readlines()
db = SimpleDatabase('feeds.json', 'feeds.log')
tmp = {}
tmp['feeds'] = {}
tmp['all_posts_sorted'] = {}
for x, feed in enumerate(feeds):
parsed = feedparser.parse(feed)
x = str(x)
tmp[x] = {}
tmp[x]['title'] = parsed.feed.title
tmp[x]['link'] = parsed.feed.link
tmp[x]['description'] = parsed.feed.description
tmp[x]['entries'] = parsed.entries
print(parsed)
tmp['feeds'][x] = {}
tmp['feeds'][x]['title'] = parsed.feed.title
tmp['feeds'][x]['link'] = parsed.feed.link
tmp['feeds'][x]['description'] = parsed.feed.description
for post in parsed.entries:
year = post['published_parsed'][0]
month = post['published_parsed'][1]
day = post['published_parsed'][2]
post_date = date(year, month, day)
if not str(post_date) in tmp['all_posts_sorted']:
tmp['all_posts_sorted'][str(post_date)] = []
post['feed_details'] = {}
post['feed_details']['title'] = parsed.feed.title
post['feed_details']['link'] = parsed.feed.link
post['feed_details']['description'] = parsed.feed.description
tmp['all_posts_sorted'][str(post_date)].append(post)
db.update(tmp)
return db
def load():
db = SimpleDatabase('feeds.json', 'feeds.log')
return db
def latest(num):
""" Placeholder request """
request = [
{
"feedtitle" : "Varia EN",
"post": "hello world",
"date" : "Monday 15th of February 2021",
"url" : "https://vvvvvvaria.org/en/rr-wireless-imagination-1.html"
}
]
""" Collect the <num> latest published posts """
db = load()
dates = [key for key in db['all_posts_sorted'].keys()]
dates.sort(reverse=True)
request = []
for date in dates:
posts = db['all_posts_sorted'][date]
for post in posts:
if len(request) < int(num):
request.append(post)
else:
break
return request
def today():
""" Collect posts from today """
db = load()
today = date.today()
request = []
today = str(date.today()).split('-')
today_year = "{:02d}".format(int(today[0]))
today_month = "{:02d}".format(int(today[1]))
today_day = "{:02d}".format(int(today[2]))
print('TODAY =', today_year, today_month, today_day)
for date_str, posts in db['all_posts_sorted'].items():
year = int(date_str.split('-')[0])
month = int(date_str.split('-')[1])
day = int(date_str.split('-')[2])
d = date(year, month, day)
# Check if any posts are published today
if d == today:
for post in posts:
request.append(post)
request = []
for x, feed in db.items():
for post in feed['entries']:
if post['published_parsed']:
year = "{:02d}".format(post['published_parsed'][0])
month = "{:02d}".format(post['published_parsed'][1])
day = "{:02d}".format(post['published_parsed'][2] + 1)
print('POST DATE =', year, month, day)
# Check if this post is published today
if year == today_year:
if month == today_month:
if day == today_day:
request.append(post)
return request
def past(days):
""" Collect posts from this week """
db = load()
point_in_the_past = date.today() - timedelta(int(days))
print(f"{ days } days in the past =", point_in_the_past)
request = []
for x, feed in db.items():
for post in feed['entries']:
if post['published_parsed']:
year = post['published_parsed'][0]
month = post['published_parsed'][1]
day = post['published_parsed'][2]
post_date = date(year, month, day)
print("post date =",post_date)
if post_date > point_in_the_past:
request.append(post)
for date_str, posts in db['all_posts_sorted'].items():
year = int(date_str.split('-')[0])
month = int(date_str.split('-')[1])
day = int(date_str.split('-')[2])
d = date(year, month, day)
if d > point_in_the_past:
for post in posts:
request.append(post)
return request
return request

31
start.py

@ -1,5 +1,6 @@
import flask
import feedtools
import json
APP = flask.Flask(__name__,
static_url_path="",
@ -11,26 +12,42 @@ def index():
db = feedtools.load()
template = flask.render_template(
"index.html",
feeds=db,
db=db,
)
return template
# @APP.route("/API/latest/<num>")
# def latest(num):
# request = feedtools.latest(num)
# return request
@APP.route("/API/latest/<num>")
def latest(num):
request = feedtools.latest(num)
response = APP.response_class(
response=json.dumps(request),
status=200,
mimetype='application/json'
)
return response
@APP.route("/API/today/")
def today():
request = feedtools.today()
return str(request)
response = APP.response_class(
response=json.dumps(request),
status=200,
mimetype='application/json'
)
return response
@APP.route("/API/past/<days>")
def past(days):
request = feedtools.past(days)
return str(request)
response = APP.response_class(
response=json.dumps(request),
status=200,
mimetype='application/json'
)
return response
if __name__ == "__main__":
feedtools.update()
APP.debug = True
APP.run(port=5678)

38
static/css/stylesheet.css

@ -1,14 +1,21 @@
body{
background-color: pink;
color: red;
/*color: red;*/
margin: 1em;
font-size: 16px;
line-height: 1.6;
}
h1,
h2{
margin: 1em;
h1#title{
width: 100%;
text-align: center;
margin: 1em auto;
}
h1#title img{
width: 500px;
}
h2{
color: fuchsia;
margin: 0 0 1em;
}
table{
@ -16,22 +23,31 @@ table{
width: 100%;
border-collapse: collapse;
}
table tr{
border-bottom: 20px solid white;
}
table td{
padding: 1em 2em;
vertical-align: top;
}
table td:first-of-type{
width: 100px;
}
table tr{
border-bottom: 20px solid white;
}
section#api{
margin: 6em 0;
margin: 6em 0em;
color: fuchsia;
}
section#api div.accesspoint{
margin: 0;
padding: 1em;
border-bottom: 20px solid yellow;
padding: 1em 2em;
border-bottom: 20px solid black;
}
a,
a:active,
a:visited,
a:hover{
text-decoration-line: underline;
color: inherit;
}

81
static/img/multifeeder.svg

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="200mm"
height="50mm"
viewBox="0 0 200 50"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="multifeeder.svg">
<defs
id="defs2">
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter863"
x="-6.5066022e-06"
width="1.000013"
y="-3.1750932e-05"
height="1.0000635">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.00051484815"
id="feGaussianBlur865" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="362.93895"
inkscape:cy="176.11126"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
width="100mm"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:43.7437px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:4,4;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter863);stroke-linecap:round"
x="4.3744469"
y="43.628365"
id="text835"><tspan
sodipodi:role="line"
id="tspan833"
x="4.3744469"
y="43.628365"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.7437px;font-family:'UKIJ Tiken';-inkscape-font-specification:'UKIJ Tiken';fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:4,4;stroke-dashoffset:0;stroke-opacity:1;stroke-linecap:round">multifeeder</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

45
templates/index.html

@ -6,33 +6,52 @@
<link rel="stylesheet" type="text/css" href="/css/stylesheet.css">
</head>
<body>
<h1>multifeeder</h1>
<h1 id="title">
<img src="/img/multifeeder.svg">
</h1>
<div align="center">(<a href="https://git.vvvvvvaria.org/varia/multifeeder/src/branch/master/feeds.txt" target="_blank">Add a feed</a>)</div>
<div align="center">Currently feeding:</div>
<br>
<br>
<table>
<tbody>
{% for x, feed in feeds.items() %}
{% for x, feed in db['feeds'].items() %}
<tr>
<td>{{ feed.title }}</td>
<td>{{ feed.link }}</td>
<td class="title">{{ feed.title }}</td>
<td class="link"><a href="{{ feed.link }}" target="_blank">{{ feed.link }}</a></td>
<td class="description">{{ feed.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
<br>
<section id="api">
<h2>API</h2>
<!-- <div class="accesspoint">
/API/latest/[num]
<div class="accesspoint">
<h2>/API/latest/[num]</h2>
For example: <a href="/API/latest/5" target="_blank">https://multi.vvvvvvaria.org/API/latest/5</a>
<br>
(for the latest 5 posts in all feeds)
<br><br>
(not there yet)
</div> -->
Format: JSON
</div>
<div class="accesspoint">
/API/today/
<h2>/API/today/</h2>
For example: <a href="/API/today/" target="_blank">https://multi.vvvvvvaria.org/API/today/</a>
<br>
(for the posts published today)
<br><br>
For example: <a href="/API/today/" target="_blank">localhost:5678/API/today/</a>
Format: JSON
</div>
<div class="accesspoint">
/API/past/[days]
<h2>/API/past/[days]</h2>
For example: <a href="/API/past/30" target="_blank">https://multi.vvvvvvaria.org/API/past/30</a>
<br>
(for all the posts published in the last 30 days)
<br><br>
For example: <a href="/API/past/30" target="_blank">localhost:5678/API/past/30</a>
Format: JSON
</div>
</section>
</body>

Loading…
Cancel
Save