JSON responses, latest + today + past requests work, web interface is pink, header image added
This commit is contained in:
parent
1bc6fbbf10
commit
c59d206bed
121
feedtools.py
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 = 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)
|
||||
|
||||
today = date.today()
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
return request
|
||||
if d > point_in_the_past:
|
||||
for post in posts:
|
||||
request.append(post)
|
||||
|
||||
return request
|
||||
|
31
start.py
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)
|
||||
|
||||
|
@ -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
Normal file
81
static/img/multifeeder.svg
Normal file
@ -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 |
@ -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]
|
||||
<br><br>
|
||||
(not there yet)
|
||||
</div> -->
|
||||
<div class="accesspoint">
|
||||
/API/today/
|
||||
<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>
|
||||
For example: <a href="/API/today/" target="_blank">localhost:5678/API/today/</a>
|
||||
Format: JSON
|
||||
</div>
|
||||
<div class="accesspoint">
|
||||
/API/past/[days]
|
||||
<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/past/30" target="_blank">localhost:5678/API/past/30</a>
|
||||
Format: JSON
|
||||
</div>
|
||||
<div class="accesspoint">
|
||||
<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>
|
||||
Format: JSON
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user