mirror of
https://github.com/MathiasDPX/blog.git
synced 2025-05-09 15:13:09 +00:00
add scrapbook
This commit is contained in:
parent
cbe04a86d1
commit
402dbfc006
8 changed files with 158 additions and 7 deletions
|
@ -1 +1,2 @@
|
|||
URL="http://127.0.0.1:5000" # URL for rss/atom feed
|
||||
URL="http://127.0.0.1:5000" # URL for rss/atom feed
|
||||
CHANNEL_LIST_TOKEN="xoxb-" # Used in channels.py
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
channels.json
|
||||
templates/articles/
|
||||
!templates/articles/loremipsum.html
|
||||
|
||||
|
|
46
channels.py
Normal file
46
channels.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
"""
|
||||
Create a dict of channel_id: channel_name for scrapbook
|
||||
"""
|
||||
|
||||
from dotenv import load_dotenv
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
ACCESS_TOKEN = os.getenv("CHANNEL_LIST_TOKEN")
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {ACCESS_TOKEN}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
params = {
|
||||
"types": "public_channel",
|
||||
"limit": 1000
|
||||
}
|
||||
|
||||
channels_map = {}
|
||||
|
||||
while True:
|
||||
response = requests.get("https://slack.com/api/conversations.list", headers=headers, params=params)
|
||||
data = response.json()
|
||||
|
||||
if not data.get("ok"):
|
||||
print("Error:", data.get("error"))
|
||||
break
|
||||
|
||||
for channel in data.get("channels", []):
|
||||
channels_map[channel["id"]] = channel["name"]
|
||||
|
||||
cursor = data.get("response_metadata", {}).get("next_cursor")
|
||||
if cursor:
|
||||
params["cursor"] = cursor
|
||||
else:
|
||||
break
|
||||
|
||||
print(f"{len(channels_map)} public channels found")
|
||||
|
||||
with open("channels.json", "w+") as f:
|
||||
json.dump(channels_map, f)
|
6
main.py
6
main.py
|
@ -5,17 +5,20 @@ from flask import Flask, render_template, request, send_file, make_response
|
|||
from feedgen.feed import FeedGenerator
|
||||
from dotenv import load_dotenv
|
||||
from routes.editor import editor_routes
|
||||
from routes.scrapbook import sp_routes
|
||||
from classes import *
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.register_blueprint(editor_routes)
|
||||
app.register_blueprint(sp_routes)
|
||||
|
||||
with open("articles.json", "r", encoding="utf-8") as f:
|
||||
articles_data = json.load(f)
|
||||
categories = {} # Category name:str -> [Article]
|
||||
articles = {} # ID:str = Article
|
||||
|
||||
# RSS Feed
|
||||
fg = FeedGenerator()
|
||||
fg.title("Mathias")
|
||||
fg.id("Mathias")
|
||||
|
@ -24,6 +27,7 @@ fg.language("en")
|
|||
fg.link(href=os.getenv("URL"))
|
||||
fg.description("Blog RSS feed")
|
||||
|
||||
# Register articles
|
||||
for article_data in articles_data:
|
||||
category_name = article_data.get("category", "Uncategorized")
|
||||
category_list = categories.get(category_name, [])
|
||||
|
@ -86,4 +90,4 @@ def article(article_id:str):
|
|||
return render_template(f"articles/{article.template}.html")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
app.run(debug=True)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
flask
|
||||
feedgen
|
||||
requests
|
||||
python-dotenv
|
57
routes/scrapbook.py
Normal file
57
routes/scrapbook.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
Display my hackclub scrapbook
|
||||
see https://scrapbook.hackclub.com/about
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template
|
||||
from datetime import datetime
|
||||
import requests
|
||||
import time
|
||||
import json
|
||||
import re
|
||||
|
||||
sp_routes = Blueprint('scrapbook', __name__, template_folder='templates')
|
||||
|
||||
lastScrapbookUpdate = 0
|
||||
scrapbookPosts = []
|
||||
|
||||
try:
|
||||
channels_maps = json.load(open('channels.json', 'r', encoding="utf-8"))
|
||||
except:
|
||||
print("channels.json not found")
|
||||
channels_maps = {}
|
||||
|
||||
@sp_routes.app_template_filter('formatDate')
|
||||
def format_date(date_str):
|
||||
date_obj = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
|
||||
return date_obj.strftime('%d/%m/%Y @ %Hh%M')
|
||||
|
||||
@sp_routes.app_template_filter('formatContent')
|
||||
def convert_slack_references(text):
|
||||
# Convert channel references
|
||||
channel_pattern = r'<#(C[A-Z0-9]+)\|>'
|
||||
|
||||
def channel_replacement(match):
|
||||
channel_id = match.group(1)
|
||||
channel_name = channels_maps.get(channel_id, channel_id)
|
||||
return f'<a href="https://hackclub.slack.com/archives/{channel_id}">#{channel_name}</a>'
|
||||
|
||||
result = re.sub(channel_pattern, channel_replacement, text)
|
||||
|
||||
return result
|
||||
|
||||
@sp_routes.route("/scrapbook")
|
||||
def scrapbook():
|
||||
"""Page linking to my scrapbook articles"""
|
||||
global lastScrapbookUpdate, scrapbookPosts
|
||||
if lastScrapbookUpdate+3600 < time.time():
|
||||
try:
|
||||
r = requests.get("https://scrapbook.hackclub.com/api/users/mathias")
|
||||
data = r.json()
|
||||
scrapbookPosts = data["posts"]
|
||||
scrapbookPosts.extend(scrapbookPosts)
|
||||
scrapbookPosts.extend(scrapbookPosts)
|
||||
lastScrapbookUpdate = time.time()
|
||||
except: pass
|
||||
|
||||
return render_template("scrapbook.html", posts=scrapbookPosts)
|
|
@ -19,11 +19,11 @@ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
|||
}
|
||||
|
||||
/* Heading Hover Effects */
|
||||
h2 a:hover::before,
|
||||
h3 a:hover::before,
|
||||
h4 a:hover::before,
|
||||
h5 a:hover::before,
|
||||
h6 a:hover::before {
|
||||
h2.chapter a:hover::before,
|
||||
h3.chapter a:hover::before,
|
||||
h4.chapter a:hover::before,
|
||||
h5.chapter a:hover::before,
|
||||
h6.chapter a:hover::before {
|
||||
content: "#";
|
||||
position: absolute;
|
||||
left: -0.75em;
|
||||
|
@ -42,6 +42,21 @@ time {
|
|||
font-size: 75%;
|
||||
}
|
||||
|
||||
#main details div {
|
||||
padding-left: 1em;
|
||||
line-height: 115%;
|
||||
}
|
||||
|
||||
#main details:open {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#main details summary {
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 500;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
|
26
templates/scrapbook.html
Normal file
26
templates/scrapbook.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block head %}
|
||||
<title>Scrapbook</title>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>Scrapook posts</h1>
|
||||
<i><h6>
|
||||
<a href="https://scrapbook.hackclub.com/mathias" style="color: #005B96;">See on scrapbook</a>
|
||||
</h6></i>
|
||||
<br>
|
||||
|
||||
{% for post in posts%}
|
||||
{% if loop.first %}
|
||||
<details id="{{ post.id }}" open>
|
||||
{% else%}
|
||||
<details id="{{ post.id }}">
|
||||
{% endif %}
|
||||
<summary>{{ post.postedAt | formatDate }}</summary>
|
||||
<div>{{ post.text | formatContent |safe }}</div>
|
||||
</details>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue