crunk
1 year ago
13 changed files with 246 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||||
|
/.venv/ |
||||
|
/__pycache__/ |
||||
|
*.pyc |
||||
|
*.egg-info/ |
||||
|
.eggs/ |
||||
|
build/ |
||||
|
dist/ |
||||
|
pip-wheel-metadata/ |
||||
|
|
||||
|
test/* |
||||
|
*.db |
@ -0,0 +1,16 @@ |
|||||
|
# Crunk columns |
||||
|
|
||||
|
crunk-columns is a work in progress website/portfolio maker. |
||||
|
part of the crunk suite of software. |
||||
|
Heavily inspired by [multifeeder](https://git.vvvvvvaria.org/varia/multifeeder) |
||||
|
This is a [PESOS](https://indieweb.org/PESOS) style website maker. |
||||
|
By filling in your desired columns in the columns.toml file you can make your own portfolio page in seconds |
||||
|
By adding your own css you can lose countless of hours tweaking everything. |
||||
|
|
||||
|
|
||||
|
## work in progress. |
||||
|
|
||||
|
|
||||
|
## POSSE is a much better approach, what are you even doing? |
||||
|
Yes, but I am lazy and I already exist on the internet and this is a way to bring |
||||
|
it all together. |
@ -0,0 +1,14 @@ |
|||||
|
import os |
||||
|
from flask import Flask |
||||
|
# from flask_sqlalchemy import SQLAlchemy |
||||
|
#db = SQLAlchemy() |
||||
|
#migrate = Migrate() |
||||
|
|
||||
|
def create_app(): |
||||
|
APP = Flask(__name__) |
||||
|
#APP.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data/crunk_data.db" |
||||
|
#APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True |
||||
|
# db.init_app(APP) |
||||
|
# migrate.init_app(APP, db, render_as_batch=True) |
||||
|
|
||||
|
return APP |
@ -0,0 +1,12 @@ |
|||||
|
class Column: |
||||
|
def __init__(self, title, entries): |
||||
|
self.title = title |
||||
|
self.entries = entries |
||||
|
self.sort_order = None |
||||
|
self.limit = None |
||||
|
|
||||
|
def set_sort_order(self, sort_order): |
||||
|
self.sort_order = sort_order |
||||
|
|
||||
|
def set_limit(self, limit): |
||||
|
self.limit = limit |
@ -0,0 +1,11 @@ |
|||||
|
[[column]] |
||||
|
id = 1 |
||||
|
urls = ["https://varia.zone/logs/x-y/feed.rss.xml","https://varia.zone/logs/x-y-protocols/feed.rss.xml"] |
||||
|
title = "code" |
||||
|
|
||||
|
[[column]] |
||||
|
id = 2 |
||||
|
urls = ["https://post.lurk.org/@cmos4040.rss"] |
||||
|
sort_order = "chronological" |
||||
|
title = "circulations" |
||||
|
limit = 100 |
@ -0,0 +1,22 @@ |
|||||
|
from feedparser import parse |
||||
|
import random |
||||
|
|
||||
|
def _parse_single_rss_feed(url): |
||||
|
feed = parse(url) |
||||
|
entries = {} |
||||
|
for entrynumber, entry in enumerate(feed.entries): |
||||
|
if entry.has_key("title"): |
||||
|
entries[entry.title] = [] |
||||
|
entrylist = entries[entry.title] |
||||
|
else: |
||||
|
title = str(entrynumber) |
||||
|
entries[title] = [] |
||||
|
entrylist = entries[title] |
||||
|
entrylist.append(entry.description) |
||||
|
return entries |
||||
|
|
||||
|
def parse_rss_feeds(urls): |
||||
|
entries = {} |
||||
|
for url in urls: |
||||
|
entries.update(_parse_single_rss_feed(url)) |
||||
|
return entries |
@ -0,0 +1,22 @@ |
|||||
|
[tool.black] |
||||
|
line-length = 79 |
||||
|
target-version = ["py37","py38","py39"] |
||||
|
|
||||
|
exclude = ''' |
||||
|
/( |
||||
|
\.eggs |
||||
|
| \.git |
||||
|
| \.hg |
||||
|
| \.mypy_cache |
||||
|
| \.tox |
||||
|
| \.venv |
||||
|
| _build |
||||
|
| buck-out |
||||
|
| build |
||||
|
| dist |
||||
|
# The following are specific to Black, you probably don't want those. |
||||
|
| blib2to3 |
||||
|
| tests/data |
||||
|
| profiling |
||||
|
)/ |
||||
|
''' |
@ -0,0 +1,20 @@ |
|||||
|
import tomli |
||||
|
from column import Column |
||||
|
from parse_rss_feeds import parse_rss_feeds |
||||
|
|
||||
|
|
||||
|
with open("columns.toml", "rb") as f: |
||||
|
feeds_dict = tomli.load(f) |
||||
|
|
||||
|
feeds_file = feeds_dict["column"] |
||||
|
columns = [] |
||||
|
for feed_from_file in feeds_file: |
||||
|
entries = parse_rss_feeds(feed_from_file["urls"]) |
||||
|
title = feed_from_file["title"] |
||||
|
column = Column(title=title, entries=entries) |
||||
|
if "limit" in feed_from_file: |
||||
|
print(feed_from_file["limit"]) |
||||
|
columns.append(column) |
||||
|
|
||||
|
for column in columns: |
||||
|
print(column.title) |
@ -0,0 +1,44 @@ |
|||||
|
from flask import ( |
||||
|
render_template, |
||||
|
redirect, |
||||
|
) |
||||
|
import tomli |
||||
|
|
||||
|
from parse_rss_feeds import parse_rss_feeds |
||||
|
from app import create_app |
||||
|
from column import Column |
||||
|
|
||||
|
APP = create_app() |
||||
|
|
||||
|
|
||||
|
@APP.route("/singlefeed") |
||||
|
def singlefeed(): |
||||
|
with open("columns.toml", "rb") as f: |
||||
|
feeds_dict = tomli.load(f) |
||||
|
feeds = feeds_dict["column"] |
||||
|
|
||||
|
feed = parse_rss_feeds(feeds[0]["urls"][0]) |
||||
|
return render_template("singlefeed.html", feed=feed) |
||||
|
|
||||
|
|
||||
|
@APP.route("/") |
||||
|
def index(): |
||||
|
with open("columns.toml", "rb") as f: |
||||
|
column_dict = tomli.load(f) |
||||
|
columns_file = column_dict["column"] |
||||
|
columns = [] |
||||
|
for column_from_file in columns_file: |
||||
|
entries = parse_rss_feeds(column_from_file["urls"]) |
||||
|
title = column_from_file["title"] |
||||
|
column = Column(title=title, entries=entries) |
||||
|
if "limit" in column_from_file: |
||||
|
column.set_limit(column_from_file["limit"]) |
||||
|
if "sort_order" in column_from_file: |
||||
|
column.set_sort_order(column_from_file["sort_order"]) |
||||
|
columns.append(column) |
||||
|
return render_template("index.html", columns=columns) |
||||
|
|
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
APP.debug = True |
||||
|
APP.run(port=5000) |
@ -0,0 +1,34 @@ |
|||||
|
body { |
||||
|
text-rendering: optimizelegibility; |
||||
|
-moz-text-size-adjust: none; |
||||
|
} |
||||
|
.crunkcolumns { |
||||
|
display: grid; |
||||
|
grid-auto-flow: column; |
||||
|
grid-gap: 10px; |
||||
|
grid-template-columns: repeat(auto-fill, 350px); |
||||
|
} |
||||
|
|
||||
|
.feed { |
||||
|
grid-template-columns: inherit; |
||||
|
} |
||||
|
|
||||
|
.feeditem { |
||||
|
display: flex; |
||||
|
width: 350px; |
||||
|
position: relative; |
||||
|
flex-direction: column; |
||||
|
box-sizing: border-box; |
||||
|
border: 1px solid black; |
||||
|
margin-top: 1px; |
||||
|
padding: 3px; |
||||
|
} |
||||
|
|
||||
|
.feeditem h2, p{ |
||||
|
margin-bottom: 3px; |
||||
|
margin-top: 3px; |
||||
|
} |
||||
|
img { |
||||
|
max-width: 100%; |
||||
|
max-height: 100%; |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang='en'> |
||||
|
<head> |
||||
|
<meta charset="utf-8" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>Title</title> |
||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/base.css')}}"> |
||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}"> |
||||
|
</head> |
||||
|
<body> |
||||
|
{% block main %} |
||||
|
{% endblock main %} |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,16 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block main %} |
||||
|
<div class="crunkcolumns"> |
||||
|
{% for column in columns %} |
||||
|
<div class="feed"> |
||||
|
<h1>{{ column.title }}</h1> |
||||
|
{% for feedtitle, text in column.entries.items() %} |
||||
|
<div class="feeditem"> |
||||
|
<h2>{{ feedtitle }}</h2> |
||||
|
{{ text[0]|safe }} |
||||
|
</div> |
||||
|
{% endfor%} |
||||
|
</div> |
||||
|
{% endfor%} |
||||
|
</div> |
||||
|
{% endblock %} |
@ -0,0 +1,10 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block main %} |
||||
|
|
||||
|
{% for feedtitle, text in feed.items() %} |
||||
|
<div class="event"> |
||||
|
<h2>{{ feedtitle }}</h2> |
||||
|
{{ text[0]|safe }} |
||||
|
</div> |
||||
|
{% endfor%} |
||||
|
{% endblock %} |
Loading…
Reference in new issue