Basic account view, suggestion algorithm and other stuff
This commit is contained in:
parent
a07a2bbaa1
commit
08e55ccdfe
3 changed files with 250 additions and 14 deletions
|
@ -62,6 +62,9 @@ def Simplify(text):
|
||||||
|
|
||||||
return ntext
|
return ntext
|
||||||
|
|
||||||
|
def Safe(text):
|
||||||
|
return text.replace("<", "<").replace(">", ">")
|
||||||
|
|
||||||
def RandString(n=50):
|
def RandString(n=50):
|
||||||
# this will make a random string
|
# this will make a random string
|
||||||
s = ""
|
s = ""
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from modules import Set
|
from modules import Set
|
||||||
|
@ -92,6 +93,24 @@ def tabs():
|
||||||
|
|
||||||
return tabs
|
return tabs
|
||||||
|
|
||||||
|
def accounts():
|
||||||
|
|
||||||
|
folder = Set.Folder()+"/accounts"
|
||||||
|
accounts = {}
|
||||||
|
|
||||||
|
for account in sorted(list(os.walk(folder))[0][2]):
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(folder+"/"+account) as o:
|
||||||
|
data = json.load(o)
|
||||||
|
accounts[account.replace(".json","")] = data
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
return accounts
|
||||||
|
|
||||||
|
|
||||||
def articles(tab):
|
def articles(tab):
|
||||||
|
|
||||||
folder = Set.Folder()+"/tabs/"+tab
|
folder = Set.Folder()+"/tabs/"+tab
|
||||||
|
@ -100,7 +119,10 @@ def articles(tab):
|
||||||
try:
|
try:
|
||||||
with open(folder+"/"+article+"/metadata.json") as o:
|
with open(folder+"/"+article+"/metadata.json") as o:
|
||||||
data = json.load(o)
|
data = json.load(o)
|
||||||
|
data["tab"] = tab
|
||||||
|
data["url"] = "/"+tab+"/"+article
|
||||||
articles[article] = data
|
articles[article] = data
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
pass
|
pass
|
||||||
|
@ -110,6 +132,85 @@ def articles(tab):
|
||||||
|
|
||||||
return articles
|
return articles
|
||||||
|
|
||||||
|
def allArticles():
|
||||||
|
|
||||||
|
articles = {}
|
||||||
|
f = Set.Folder()
|
||||||
|
for tab in list(os.walk(f+"/tabs/"))[0][1]:
|
||||||
|
folder = f+"/tabs/"+tab
|
||||||
|
|
||||||
|
for article in list(os.walk(folder))[0][1]:
|
||||||
|
try:
|
||||||
|
with open(folder+"/"+article+"/metadata.json") as o:
|
||||||
|
data = json.load(o)
|
||||||
|
data["tab"] = tab
|
||||||
|
data["url"] = "/"+tab+"/"+article
|
||||||
|
articles[article] = data
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Sorting articles based on timestamp
|
||||||
|
articles = {k:articles[k] for k in sorted(articles, key=lambda y: articles[y]["timestamp"], reverse=True)}
|
||||||
|
return articles
|
||||||
|
|
||||||
|
def randomArticles():
|
||||||
|
|
||||||
|
articles = {}
|
||||||
|
f = Set.Folder()
|
||||||
|
for tab in list(os.walk(f+"/tabs/"))[0][1]:
|
||||||
|
folder = f+"/tabs/"+tab
|
||||||
|
|
||||||
|
for article in list(os.walk(folder))[0][1]:
|
||||||
|
try:
|
||||||
|
with open(folder+"/"+article+"/metadata.json") as o:
|
||||||
|
data = json.load(o)
|
||||||
|
data["tab"] = tab
|
||||||
|
data["url"] = "/"+tab+"/"+article
|
||||||
|
articles[article] = data
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Randomizing Articles.
|
||||||
|
newarticles = {}
|
||||||
|
while articles:
|
||||||
|
article = random.choice(list(articles.keys()))
|
||||||
|
newarticles[article] = articles.pop(article)
|
||||||
|
|
||||||
|
return newarticles
|
||||||
|
|
||||||
|
def suggestedArticles(cookie, random=False):
|
||||||
|
|
||||||
|
if not random:
|
||||||
|
articles = allArticles()
|
||||||
|
else:
|
||||||
|
articles = randomArticles()
|
||||||
|
|
||||||
|
# Suggesting unread articles.
|
||||||
|
newarticles = {}
|
||||||
|
move = []
|
||||||
|
for article in articles:
|
||||||
|
if cookie not in articles[article].get("views", {}).get("viewers", []):
|
||||||
|
move.append(article)
|
||||||
|
|
||||||
|
for article in move:
|
||||||
|
newarticles[article] = articles[article]
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
if article not in move:
|
||||||
|
newarticles[article] = articles[article]
|
||||||
|
|
||||||
|
return newarticles
|
||||||
|
|
||||||
|
def previewsToSize(text):
|
||||||
|
|
||||||
|
# Calculates roughly how many previews to fit any
|
||||||
|
# given article.
|
||||||
|
|
||||||
|
# A thousand character article is about 4 articles.
|
||||||
|
return int(round(len(text)/2500))
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -150,7 +251,21 @@ def MainPage(server):
|
||||||
|
|
||||||
html = html + "</center>"
|
html = html + "</center>"
|
||||||
|
|
||||||
for i in range(50): html = html + "<br>"
|
# Trending articles
|
||||||
|
|
||||||
|
html = html + '<div class="flexity">'
|
||||||
|
|
||||||
|
trends = suggestedArticles(server.cookie)
|
||||||
|
Buffer = 20
|
||||||
|
for n, article in enumerate(trends):
|
||||||
|
|
||||||
|
if n >= Buffer: break
|
||||||
|
|
||||||
|
article = trends[article]
|
||||||
|
html = html + ArticlePreview(article, Tabs, server.cookie)
|
||||||
|
|
||||||
|
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
html = html + Footer()
|
html = html + Footer()
|
||||||
|
|
||||||
|
@ -208,9 +323,7 @@ def ListPage(server, tab):
|
||||||
if n < From: continue
|
if n < From: continue
|
||||||
if n >= To: break
|
if n >= To: break
|
||||||
|
|
||||||
html = html + ArticlePreview(Articles[article],
|
html = html + ArticlePreview(Articles[article], Tabs, server.cookie)
|
||||||
tab+"/"+article,
|
|
||||||
tab, Tabs)
|
|
||||||
rendered += 1
|
rendered += 1
|
||||||
|
|
||||||
html = html + '</div><br>'
|
html = html + '</div><br>'
|
||||||
|
@ -242,10 +355,11 @@ def ArticlePage(server, url):
|
||||||
tab, article = url.split("/")
|
tab, article = url.split("/")
|
||||||
Tabs = tabs()
|
Tabs = tabs()
|
||||||
Articles = articles(tab)
|
Articles = articles(tab)
|
||||||
|
f = Set.Folder()
|
||||||
|
|
||||||
# Generating <head>
|
# Generating <head>
|
||||||
html = head(title = Tabs.get(tab, {}).get("title", tab),
|
html = head(title = Articles.get(article, {}).get("title", article),
|
||||||
description = "",
|
description = Articles.get(article, {}).get("description", ""),
|
||||||
config = config
|
config = config
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -288,18 +402,112 @@ def ArticlePage(server, url):
|
||||||
|
|
||||||
|
|
||||||
html = html + '<div class="dark_box">'
|
html = html + '<div class="dark_box">'
|
||||||
html = html + markdown.convert(Set.Folder()+"/tabs/"+tab+"/"+article+"/text.md")
|
html = html + markdown.convert(f+"/tabs/"+tab+"/"+article+"/text.md")
|
||||||
html = html + '</div>'
|
html = html + '</div>'
|
||||||
|
|
||||||
html = html + '</div>'
|
html = html + '</div>'
|
||||||
|
|
||||||
# Thumbnail and suggestions
|
# Thumbnail and suggestions
|
||||||
|
|
||||||
|
html = html + '<div class="checklist_section_article">'
|
||||||
|
|
||||||
|
thumbnail = Articles.get(article, {}).get("thumbnail")
|
||||||
|
if thumbnail:
|
||||||
|
|
||||||
|
html = html + '<div class="article_box"><br>'
|
||||||
|
html = html + '<img style="min-width:100%; width:100%" src="'+thumbnail+'">'
|
||||||
|
html = html + '<br><br></div>'
|
||||||
|
|
||||||
|
suggestions = suggestedArticles(server.cookie, random=True)
|
||||||
|
toomuch = previewsToSize(open(f+"/tabs/"+tab+"/"+article+"/text.md").read())
|
||||||
|
|
||||||
|
for n, title in enumerate(suggestions):
|
||||||
|
|
||||||
|
if server.path in suggestions[title].get("url") :
|
||||||
|
continue
|
||||||
|
|
||||||
|
if n > toomuch:
|
||||||
|
break
|
||||||
|
|
||||||
|
article = suggestions[title]
|
||||||
|
html = html + ArticlePreview(article, Tabs, server.cookie)
|
||||||
|
html = html + ""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
send(server, html, 200)
|
send(server, html, 200)
|
||||||
|
|
||||||
|
def AccountPage(server, account):
|
||||||
|
|
||||||
|
config = Set.Load()
|
||||||
|
Accounts = accounts()
|
||||||
|
Tabs = tabs()
|
||||||
|
Articles = allArticles()
|
||||||
|
f = Set.Folder()
|
||||||
|
|
||||||
|
# Generating <head>
|
||||||
|
html = head(title = Safe(Accounts.get(account, {}).get("title", account)),
|
||||||
|
description = Safe(Accounts.get(account, {}).get("bio" , "")),
|
||||||
|
config = config
|
||||||
|
)
|
||||||
|
|
||||||
|
html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet"))
|
||||||
|
|
||||||
|
# Name and bio
|
||||||
|
|
||||||
|
html = html + '<div class="middle_section_article">'
|
||||||
|
|
||||||
|
html = html + '<div class="dark_box">'
|
||||||
|
html = html +"<center><h1>"+Accounts.get(account, {}).get("title", account)+"</h1></center>"
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
html = html + '<div class="dark_box">'
|
||||||
|
html = html +"<center>Invited by:<br>"+User(Accounts.get(account, {}).get("invited_by", account))+"</center>"
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
bio = Safe(Accounts.get(account, {}).get("bio" , ""))
|
||||||
|
if bio:
|
||||||
|
html = html + '<div class="dark_box">'
|
||||||
|
html = html + markdown.convert(bio, False)
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
|
||||||
|
# Posts by this account
|
||||||
|
|
||||||
|
html = html + '<div class="flexity">'
|
||||||
|
|
||||||
|
for article in Articles:
|
||||||
|
|
||||||
|
if Articles[article].get("author") != account:
|
||||||
|
continue
|
||||||
|
|
||||||
|
html = html + ArticlePreview(Articles[article], Tabs, server.cookie)
|
||||||
|
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
# Thumbnail and suggestions
|
||||||
|
|
||||||
|
html = html + '<div class="checklist_section_article">'
|
||||||
|
|
||||||
|
avatar = Safe(Accounts.get(account, {}).get("avatar" , ""))
|
||||||
|
if avatar:
|
||||||
|
html = html + '<div class="article_box"><br>'
|
||||||
|
html = html + '<img style="min-width:100%; width:100%" src="'+avatar+'">'
|
||||||
|
html = html + '<br><br></div>'
|
||||||
|
|
||||||
|
# Invited
|
||||||
|
|
||||||
|
invited = Accounts.get(account, {}).get("invited", [])
|
||||||
|
if invited:
|
||||||
|
html = html + '<center><div class="button">Invited:</div></center>'
|
||||||
|
for username in invited:
|
||||||
|
html = html + '<div class="dark_box">'
|
||||||
|
html = html + '<center>' + User(username) + '</center>\n'
|
||||||
|
html = html + '</div>'
|
||||||
|
|
||||||
|
send(server, html, 200)
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -320,17 +528,22 @@ def Button(text, link, icon="", image=""):
|
||||||
"""
|
"""
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def ArticlePreview(article, url, tab, Tabs):
|
def ArticlePreview(article, Tabs, cookie=""):
|
||||||
|
|
||||||
html = """
|
html = """
|
||||||
|
|
||||||
<div class="article_box">
|
<div class="article_box">
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
url, tab = article.get("url", ""), article.get("tab","")
|
||||||
|
|
||||||
|
sup = ""
|
||||||
|
if cookie not in article.get("views", {}).get("viewers", ""):
|
||||||
|
sup = '<center><sup><b> Unread </b></sup></center><br>'
|
||||||
|
|
||||||
html = html + '<a href="'+url+'"><h1>'
|
html = html + '<a href="'+url+'"><h1>'
|
||||||
html = html + '<img src="/icon/'+Tabs.get(tab, {}).get("icon", "folder")+'" style="vertical-align: middle">'
|
html = html + '<img src="/icon/'+Tabs.get(tab, {}).get("icon", "folder")+'" style="vertical-align: middle">'
|
||||||
html = html + article.get("title", "")+"</h1></a>\n"
|
html = html + article.get("title", "")+"</h1></a>"+sup+"\n"
|
||||||
|
|
||||||
if "thumbnail" in article:
|
if "thumbnail" in article:
|
||||||
html = html + '<center><a href="'+url+'"><img src="'+article["thumbnail"]+'"></a></center>'
|
html = html + '<center><a href="'+url+'"><img src="'+article["thumbnail"]+'"></a></center>'
|
||||||
|
@ -344,7 +557,7 @@ def ArticlePreview(article, url, tab, Tabs):
|
||||||
except: comments = "0"
|
except: comments = "0"
|
||||||
html = html +'<br><center> 👁 '+views+' 💬 '+comments+' </center>'
|
html = html +'<br><center> 👁 '+views+' 💬 '+comments+' </center>'
|
||||||
|
|
||||||
html = html + "<br>"+article.get("description", "")+"<br><br>"
|
html = html + "<br>"+markdown.convert(article.get("description", ""), False)+"<br><br>"
|
||||||
html = html + '</div>\n'
|
html = html + '</div>\n'
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
@ -376,9 +589,10 @@ def User(username, stretch=False):
|
||||||
account = {}
|
account = {}
|
||||||
|
|
||||||
# We are doing a lot of reductions in case somebody sneaks html code.
|
# We are doing a lot of reductions in case somebody sneaks html code.
|
||||||
avatar = account.get("avatar", "/pictures/monkey.png").replace("<", "<").replace(">", ">")
|
avatar = Safe(account.get("avatar", ""))
|
||||||
username = username.replace("&", "&").replace("<", "<").replace(">", ">")
|
if not avatar: avatar = "/pictures/monkey.png"
|
||||||
title = account.get("title", username).replace("&", "&").replace("<", "<").replace(">", ">")
|
username = Safe(username)
|
||||||
|
title = Safe(account.get("title", username))
|
||||||
html = '<img style="height:50px;vertical-align: middle" src="'+avatar+'"> <a href="/account/'+username+'">'+title+'</a></center>\n'
|
html = '<img style="height:50px;vertical-align: middle" src="'+avatar+'"> <a href="/account/'+username+'">'+title+'</a></center>\n'
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
@ -429,5 +643,19 @@ def Graph(server, url):
|
||||||
|
|
||||||
html = html + '<div style="top:'+str(60-height)+'%;right:'+str((nd)*(width))+'%; width:'+str(max(width-0.5,0.5))+'%; height:'+str(height)+'%" title="'+str(date)+' - '+str(amount)+' views" class="graph_line"></div>\n'
|
html = html + '<div style="top:'+str(60-height)+'%;right:'+str((nd)*(width))+'%; width:'+str(max(width-0.5,0.5))+'%; height:'+str(height)+'%" title="'+str(date)+' - '+str(amount)+' views" class="graph_line"></div>\n'
|
||||||
|
|
||||||
|
|
||||||
|
# Saving the view
|
||||||
|
if server.cookie not in article.get("views", {}).get("viewers", []):
|
||||||
|
|
||||||
|
try:
|
||||||
|
article["views"]["amount"] += 1
|
||||||
|
article["views"]["viewers"].append(server.cookie)
|
||||||
|
|
||||||
|
with open(Set.Folder()+"/tabs"+url+"/metadata.json", "w") as save:
|
||||||
|
json.dump(article, save, indent=4)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
send(server, html, 200)
|
send(server, html, 200)
|
||||||
|
|
|
@ -66,6 +66,11 @@ class handler(BaseHTTPRequestHandler):
|
||||||
if "?" in url: url = url[:url.find("?")]
|
if "?" in url: url = url[:url.find("?")]
|
||||||
Render.ArticlePage(self, url)
|
Render.ArticlePage(self, url)
|
||||||
|
|
||||||
|
elif self.path[1:].startswith("account"):
|
||||||
|
url = self.path[9:]
|
||||||
|
if "?" in url: url = url[:url.find("?")]
|
||||||
|
Render.AccountPage(self, url)
|
||||||
|
|
||||||
elif self.path.startswith("/graph/"):
|
elif self.path.startswith("/graph/"):
|
||||||
url = self.path[6:]
|
url = self.path[6:]
|
||||||
if "?" in url: url = url[:url.find("?")]
|
if "?" in url: url = url[:url.find("?")]
|
||||||
|
|
Loading…
Add table
Reference in a new issue