openwrite 0.10.1__tar.gz → 0.10.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openwrite-0.10.1/openwrite.egg-info → openwrite-0.10.3}/PKG-INFO +39 -1
- {openwrite-0.10.1 → openwrite-0.10.3}/README.md +1 -12
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/cli.py +3 -4
- openwrite-0.10.3/openwrite/gemini_multi.py +117 -0
- openwrite-0.10.3/openwrite/gemini_single.py +84 -0
- openwrite-0.10.3/openwrite/static/logo.png +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3/openwrite.egg-info}/PKG-INFO +39 -1
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite.egg-info/SOURCES.txt +2 -1
- {openwrite-0.10.1 → openwrite-0.10.3}/pyproject.toml +7 -1
- openwrite-0.10.1/openwrite/launch_gemini.py +0 -8
- openwrite-0.10.1/openwrite/static/logo.png +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/LICENSE +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/MANIFEST.in +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/__init__.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/db/__init__.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/db/base.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/admin.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/auth.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/blog.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/dashboard.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/federation.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/main.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/routes/upload.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/IBMPlexSans-Regular.ttf +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/Merriweather.ttf +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/avatar.png +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/favicon.ico +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/chart.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/highlight.min.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/openwrite.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/papaparse.min.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/showdown.min.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/showdown.min.js.map +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/site.compat.min.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/script/site.min.js +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/hl.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/style.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/light.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/obscura.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/stickynote.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/terminal.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/warmnight.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/static/style/themes/windows98.css +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/admin.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/blog.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/blog_footer.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/blog_header.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/blog_preview.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/changepw.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/create.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/dashboard.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/discover.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/edit.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/footer.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/header.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/import.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/index.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/instances.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/login.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/new_post.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/post.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/preview.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/register.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/settings.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/templates/stats.html +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/create_db.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/db.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/helpers.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/i18n.json +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/models.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite/utils/translations.py +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite.egg-info/dependency_links.txt +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite.egg-info/entry_points.txt +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite.egg-info/requires.txt +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/openwrite.egg-info/top_level.txt +0 -0
- {openwrite-0.10.1 → openwrite-0.10.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwrite
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
5
5
|
Version 3, 19 November 2007
|
|
6
6
|
|
|
@@ -663,6 +663,10 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
|
663
663
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
664
664
|
<https://www.gnu.org/licenses/>.
|
|
665
665
|
|
|
666
|
+
Project-URL: Homepage, https://openwrite.io
|
|
667
|
+
Project-URL: GitHub repository, https://github.com/openwriteio/openwrite
|
|
668
|
+
Requires-Python: >=3.11
|
|
669
|
+
Description-Content-Type: text/markdown
|
|
666
670
|
License-File: LICENSE
|
|
667
671
|
Requires-Dist: flask
|
|
668
672
|
Requires-Dist: python-dotenv
|
|
@@ -682,3 +686,37 @@ Requires-Dist: md2gemini
|
|
|
682
686
|
Requires-Dist: gmcapsule
|
|
683
687
|
Requires-Dist: user-agents
|
|
684
688
|
Dynamic: license-file
|
|
689
|
+
|
|
690
|
+

|
|
691
|
+
openwrite is a minimalist blogging platform built for writing freely, hosting independently, and publishing without noise.
|
|
692
|
+
|
|
693
|
+
[](CHANGELOG.md)
|
|
694
|
+
[](LICENSE)
|
|
695
|
+

|
|
696
|
+

|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## Features
|
|
701
|
+
|
|
702
|
+
- Multiple blogs per user(limit defined in .env)
|
|
703
|
+
- Single-blog mode
|
|
704
|
+
- Supports sqlite and mysql databases
|
|
705
|
+
- Upload images to local storage or bunny cdn
|
|
706
|
+
- Simple markdown editor in posting
|
|
707
|
+
- Discover section
|
|
708
|
+
- Privacy:
|
|
709
|
+
- Set if blog should be indexed in search engines
|
|
710
|
+
- Set if post should be listed in "Discover" section
|
|
711
|
+
- Set if username should appear in post page (anonymous posts)
|
|
712
|
+
- Lightweight
|
|
713
|
+
- No tracking, only data collected is anonymized(hashed) IP for post view counting and likes
|
|
714
|
+
- Custom CSS per blog
|
|
715
|
+
- Federation using ActivityPub protocol: Follow and Like
|
|
716
|
+
- Likes system
|
|
717
|
+
- Posts importing from xml/csv
|
|
718
|
+
- Blog themes
|
|
719
|
+
- Gemini protocol
|
|
720
|
+
- Statistics per post
|
|
721
|
+
|
|
722
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
openwrite is a minimalist blogging platform built for writing freely, hosting independently, and publishing without noise.
|
|
3
3
|
|
|
4
4
|
[](CHANGELOG.md)
|
|
@@ -30,15 +30,4 @@ openwrite is a minimalist blogging platform built for writing freely, hosting in
|
|
|
30
30
|
- Gemini protocol
|
|
31
31
|
- Statistics per post
|
|
32
32
|
|
|
33
|
-
## Installation
|
|
34
|
-
|
|
35
|
-
For now, *openwrite* is in development phase. Make sure to understand that the project can have bugs and/or security vulnerabilities at the moment.
|
|
36
|
-
|
|
37
|
-
If you want to install the package now for testing or contributing:
|
|
38
|
-
|
|
39
|
-
1. Clone this repository
|
|
40
|
-
2. `pip install .` for installation
|
|
41
|
-
3. `openwrite init` for initialization of .env
|
|
42
|
-
4. `openwrite run` for foregound run, `openwrite run -d` for deamonized run
|
|
43
|
-
5. `openwrite debugrun` for debug run(werkzeug)
|
|
44
33
|
|
|
@@ -16,7 +16,8 @@ import bcrypt
|
|
|
16
16
|
|
|
17
17
|
load_dotenv()
|
|
18
18
|
f_abs_path = os.path.abspath(__file__)
|
|
19
|
-
|
|
19
|
+
lib_cwd = "/".join(f_abs_path.split("/")[:-1])
|
|
20
|
+
cwd = os.getcwd()
|
|
20
21
|
env = f"{cwd}/.env"
|
|
21
22
|
|
|
22
23
|
def print_banner():
|
|
@@ -85,11 +86,9 @@ def init():
|
|
|
85
86
|
os.makedirs(f"{cwd}/gemini/.certs", exist_ok=True)
|
|
86
87
|
subprocess.run(["openssl", "req", "-x509", "-newkey", "rsa:4096", "-keyout", f"{cwd}/gemini/.certs/key.pem", "-out", f"{cwd}/gemini/.certs/cert.pem", "-days", "365", "-nodes", "-subj", f"/CN={domain}"], check=True)
|
|
87
88
|
if mode == 1:
|
|
88
|
-
os.rename(f"{
|
|
89
|
-
os.remove(f"{cwd}/gemini_single.py")
|
|
89
|
+
os.rename(f"{lib_cwd}/gemini_multi.py", f"{cwd}/gemini/mod/10_openwrite.py")
|
|
90
90
|
elif mode == 2:
|
|
91
91
|
os.rename(f"{cwd}/gemini_single.py", f"{cwd}/gemini/mod/10_openwrite.py")
|
|
92
|
-
os.remove(f"{cwd}/gemini_multi.py")
|
|
93
92
|
|
|
94
93
|
logs_enabled = click.confirm("Enable logging?", default=True)
|
|
95
94
|
if logs_enabled:
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import os, subprocess
|
|
2
|
+
from dotenv import load_dotenv
|
|
3
|
+
from openwrite.utils.db import init_engine, SessionLocal
|
|
4
|
+
from openwrite.utils.models import Blog, Post, User, View
|
|
5
|
+
from openwrite.utils.helpers import anonymize
|
|
6
|
+
from md2gemini import md2gemini
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
session = None
|
|
9
|
+
|
|
10
|
+
openwrite_logo = """
|
|
11
|
+
|
|
12
|
+
.-. /
|
|
13
|
+
.-._..-. .-.. .-. `) ( ).--.`-'---/---.-.
|
|
14
|
+
( ) / )./.-'_)/ )/ . )/ / / ./.-'_
|
|
15
|
+
`-' /`-' (__.''/ ((_.' `-'/ _.(__. / (__.'
|
|
16
|
+
/ `-
|
|
17
|
+
quiet space for loud thoughts
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def root(req):
|
|
21
|
+
global session
|
|
22
|
+
resp = f"```\n{openwrite_logo}\n```"
|
|
23
|
+
resp += "\nopenwrite.io is a minimalist blogging platform built for writing freely, hosting independently, and publishing without noise. To create your own blog, visit:\n"
|
|
24
|
+
resp += "=> https://openwrite.io openwrite.io\n"
|
|
25
|
+
resp += "In here you can read posts published.\n"
|
|
26
|
+
resp += "\n## 🗞️ Latest posts:\n"
|
|
27
|
+
try:
|
|
28
|
+
posts = (session.query(Post).filter_by(feed="1").order_by(Post.id.desc()).limit(10).all())
|
|
29
|
+
for p in posts:
|
|
30
|
+
blog = session.query(Blog).filter_by(id=p.blog).first()
|
|
31
|
+
resp += f"\n{p.date} - 📓 {blog.title}\n"
|
|
32
|
+
resp += f"=> /b/{blog.name}/{p.link} {p.title}\n"
|
|
33
|
+
return resp
|
|
34
|
+
|
|
35
|
+
finally:
|
|
36
|
+
session.close()
|
|
37
|
+
|
|
38
|
+
def blog_index(req):
|
|
39
|
+
global session
|
|
40
|
+
path = req.path
|
|
41
|
+
if len(path.split("/")) == 3:
|
|
42
|
+
blogname = path.split("/")[2]
|
|
43
|
+
try:
|
|
44
|
+
blog = session.query(Blog).filter_by(name=blogname).first()
|
|
45
|
+
if not blog:
|
|
46
|
+
return "not found"
|
|
47
|
+
posts = (session.query(Post)
|
|
48
|
+
.filter_by(blog=blog.id)
|
|
49
|
+
.order_by(Post.id.desc())
|
|
50
|
+
.all())
|
|
51
|
+
body = f"# 📓 {blog.title}\n\n"
|
|
52
|
+
body += md2gemini(blog.description_raw.replace("#", ""))
|
|
53
|
+
body += "\n--------------------------------------------------\n"
|
|
54
|
+
body += "### Posts:\n\n"
|
|
55
|
+
for post in posts:
|
|
56
|
+
body += f"=> /b/{blogname}/{post.link} {post.title}\n"
|
|
57
|
+
return body
|
|
58
|
+
finally:
|
|
59
|
+
session.close()
|
|
60
|
+
elif len(path.split("/")) == 4:
|
|
61
|
+
|
|
62
|
+
blogname = path.split("/")[2]
|
|
63
|
+
slug = path.split("/")[3]
|
|
64
|
+
try:
|
|
65
|
+
blog = session.query(Blog).filter_by(name=blogname).first()
|
|
66
|
+
if not blog:
|
|
67
|
+
return "not found"
|
|
68
|
+
|
|
69
|
+
post = (session.query(Post)
|
|
70
|
+
.filter_by(blog=blog.id, link=slug)
|
|
71
|
+
.first())
|
|
72
|
+
if not post:
|
|
73
|
+
return "not found"
|
|
74
|
+
user = session.query(User).filter_by(id=blog.owner).first()
|
|
75
|
+
|
|
76
|
+
now = datetime.now(timezone.utc)
|
|
77
|
+
ip = anonymize(req.remote_address[0])
|
|
78
|
+
v = session.query(View).filter(View.blog==blog.id, View.post==post.id, View.hash==ip).count()
|
|
79
|
+
if v < 1:
|
|
80
|
+
new_view = View(blog=blog.id, post=post.id, hash=ip, date=now, agent="gemini")
|
|
81
|
+
session.add(new_view)
|
|
82
|
+
session.commit()
|
|
83
|
+
|
|
84
|
+
post.authorname = user.username
|
|
85
|
+
gemtext = f"=> /b/{blog.name} 📓 {blog.title}\n"
|
|
86
|
+
gemtext += f"# 🧾 {post.title}\n\n"
|
|
87
|
+
gemtext += f"{post.date} "
|
|
88
|
+
if post.author != "0":
|
|
89
|
+
gemtext += f"by {post.authorname}"
|
|
90
|
+
gemtext += "\n--------------------------------------------------\n"
|
|
91
|
+
gemtext += f"\n\n{md2gemini(post.content_raw)}"
|
|
92
|
+
return gemtext
|
|
93
|
+
|
|
94
|
+
finally:
|
|
95
|
+
session.close()
|
|
96
|
+
|
|
97
|
+
else:
|
|
98
|
+
return "not found"
|
|
99
|
+
|
|
100
|
+
def init(capsule):
|
|
101
|
+
global session
|
|
102
|
+
load_dotenv()
|
|
103
|
+
init_engine(os.getenv("DB_TYPE", "sqlite"),
|
|
104
|
+
os.getenv("DB_PATH", "db.sqlite"))
|
|
105
|
+
|
|
106
|
+
from openwrite.utils.db import SessionLocal
|
|
107
|
+
session = SessionLocal
|
|
108
|
+
|
|
109
|
+
capsule.add("/",
|
|
110
|
+
root,
|
|
111
|
+
protocol='gemini')
|
|
112
|
+
|
|
113
|
+
capsule.add("/b/*",
|
|
114
|
+
blog_index,
|
|
115
|
+
protocol='gemini')
|
|
116
|
+
|
|
117
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import os, subprocess
|
|
2
|
+
from dotenv import load_dotenv
|
|
3
|
+
from openwrite.utils.db import init_engine, SessionLocal
|
|
4
|
+
from openwrite.utils.models import Blog, Post, User, View
|
|
5
|
+
from openwrite.utils.helpers import anonymize
|
|
6
|
+
from md2gemini import md2gemini
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
session = None
|
|
9
|
+
|
|
10
|
+
def blog_index(req):
|
|
11
|
+
global session
|
|
12
|
+
try:
|
|
13
|
+
blog = session.query(Blog).filter_by(name="default").first()
|
|
14
|
+
posts = (session.query(Post)
|
|
15
|
+
.filter_by(blog=blog.id)
|
|
16
|
+
.order_by(Post.id.desc())
|
|
17
|
+
.all())
|
|
18
|
+
body = f"# 📓 {blog.title}\n\n"
|
|
19
|
+
body += md2gemini(blog.description_raw.replace("#", ""))
|
|
20
|
+
body += "\n--------------------------------------------------\n"
|
|
21
|
+
body += "### Posts:\n\n"
|
|
22
|
+
for post in posts:
|
|
23
|
+
body += f"=> /p/{post.link} {post.title}\n"
|
|
24
|
+
return body
|
|
25
|
+
finally:
|
|
26
|
+
session.close()
|
|
27
|
+
|
|
28
|
+
def blog_post(req):
|
|
29
|
+
global session
|
|
30
|
+
path = req.path
|
|
31
|
+
if len(path.split("/")) == 3:
|
|
32
|
+
|
|
33
|
+
slug = path.split("/")[2]
|
|
34
|
+
try:
|
|
35
|
+
blog = session.query(Blog).filter_by(name="default").first()
|
|
36
|
+
post = (session.query(Post)
|
|
37
|
+
.filter_by(blog=blog.id, link=slug)
|
|
38
|
+
.first())
|
|
39
|
+
if not post:
|
|
40
|
+
return "not found"
|
|
41
|
+
user = session.query(User).filter_by(id=blog.owner).first()
|
|
42
|
+
|
|
43
|
+
now = datetime.now(timezone.utc)
|
|
44
|
+
ip = anonymize(req.remote_address[0])
|
|
45
|
+
v = session.query(View).filter(View.blog==blog.id, View.post==post.id, View.hash==ip).count()
|
|
46
|
+
if v < 1:
|
|
47
|
+
new_view = View(blog=blog.id, post=post.id, hash=ip, date=now, agent="gemini")
|
|
48
|
+
session.add(new_view)
|
|
49
|
+
session.commit()
|
|
50
|
+
|
|
51
|
+
post.authorname = user.username
|
|
52
|
+
gemtext = f"=> /b/{blog.name} 📓 {blog.title}\n"
|
|
53
|
+
gemtext += f"# 🧾 {post.title}\n\n"
|
|
54
|
+
gemtext += f"{post.date} "
|
|
55
|
+
if post.author != "0":
|
|
56
|
+
gemtext += f"by {post.authorname}"
|
|
57
|
+
gemtext += "\n--------------------------------------------------\n"
|
|
58
|
+
gemtext += f"\n\n{md2gemini(post.content_raw)}"
|
|
59
|
+
return gemtext
|
|
60
|
+
|
|
61
|
+
finally:
|
|
62
|
+
session.close()
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
return "not found"
|
|
66
|
+
|
|
67
|
+
def init(capsule):
|
|
68
|
+
global session
|
|
69
|
+
load_dotenv()
|
|
70
|
+
init_engine(os.getenv("DB_TYPE", "sqlite"),
|
|
71
|
+
os.getenv("DB_PATH", "db.sqlite"))
|
|
72
|
+
|
|
73
|
+
from openwrite.utils.db import SessionLocal
|
|
74
|
+
session = SessionLocal
|
|
75
|
+
|
|
76
|
+
capsule.add("/",
|
|
77
|
+
blog_index,
|
|
78
|
+
protocol='gemini')
|
|
79
|
+
|
|
80
|
+
capsule.add("/p/*",
|
|
81
|
+
blog_post,
|
|
82
|
+
protocol='gemini')
|
|
83
|
+
|
|
84
|
+
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwrite
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
5
5
|
Version 3, 19 November 2007
|
|
6
6
|
|
|
@@ -663,6 +663,10 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
|
663
663
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
664
664
|
<https://www.gnu.org/licenses/>.
|
|
665
665
|
|
|
666
|
+
Project-URL: Homepage, https://openwrite.io
|
|
667
|
+
Project-URL: GitHub repository, https://github.com/openwriteio/openwrite
|
|
668
|
+
Requires-Python: >=3.11
|
|
669
|
+
Description-Content-Type: text/markdown
|
|
666
670
|
License-File: LICENSE
|
|
667
671
|
Requires-Dist: flask
|
|
668
672
|
Requires-Dist: python-dotenv
|
|
@@ -682,3 +686,37 @@ Requires-Dist: md2gemini
|
|
|
682
686
|
Requires-Dist: gmcapsule
|
|
683
687
|
Requires-Dist: user-agents
|
|
684
688
|
Dynamic: license-file
|
|
689
|
+
|
|
690
|
+

|
|
691
|
+
openwrite is a minimalist blogging platform built for writing freely, hosting independently, and publishing without noise.
|
|
692
|
+
|
|
693
|
+
[](CHANGELOG.md)
|
|
694
|
+
[](LICENSE)
|
|
695
|
+

|
|
696
|
+

|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## Features
|
|
701
|
+
|
|
702
|
+
- Multiple blogs per user(limit defined in .env)
|
|
703
|
+
- Single-blog mode
|
|
704
|
+
- Supports sqlite and mysql databases
|
|
705
|
+
- Upload images to local storage or bunny cdn
|
|
706
|
+
- Simple markdown editor in posting
|
|
707
|
+
- Discover section
|
|
708
|
+
- Privacy:
|
|
709
|
+
- Set if blog should be indexed in search engines
|
|
710
|
+
- Set if post should be listed in "Discover" section
|
|
711
|
+
- Set if username should appear in post page (anonymous posts)
|
|
712
|
+
- Lightweight
|
|
713
|
+
- No tracking, only data collected is anonymized(hashed) IP for post view counting and likes
|
|
714
|
+
- Custom CSS per blog
|
|
715
|
+
- Federation using ActivityPub protocol: Follow and Like
|
|
716
|
+
- Likes system
|
|
717
|
+
- Posts importing from xml/csv
|
|
718
|
+
- Blog themes
|
|
719
|
+
- Gemini protocol
|
|
720
|
+
- Statistics per post
|
|
721
|
+
|
|
722
|
+
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openwrite"
|
|
7
|
-
version = "0.10.
|
|
7
|
+
version = "0.10.3"
|
|
8
8
|
license = { file = "LICENSE" }
|
|
9
9
|
dependencies = [
|
|
10
10
|
"flask",
|
|
@@ -25,6 +25,12 @@ dependencies = [
|
|
|
25
25
|
"gmcapsule",
|
|
26
26
|
"user-agents"
|
|
27
27
|
]
|
|
28
|
+
requires-python = ">=3.11"
|
|
29
|
+
readme = "README.md"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
"Homepage" = "https://openwrite.io"
|
|
33
|
+
"GitHub repository" = "https://github.com/openwriteio/openwrite"
|
|
28
34
|
|
|
29
35
|
[project.scripts]
|
|
30
36
|
openwrite = "openwrite.cli:cli"
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|