diff --git a/lib/awesome-privacy-readme-gen.py b/lib/awesome-privacy-readme-gen.py
index 396006c..9c6d623 100644
--- a/lib/awesome-privacy-readme-gen.py
+++ b/lib/awesome-privacy-readme-gen.py
@@ -1,13 +1,13 @@
"""
Reads app list from awesome-privacy.yml,
-formats into markdown, and inserts into README.md
+formats into markdown, and inserts into README.md
"""
import os
import re
import yaml
import logging
-from urllib.parse import urlparse
+from urllib.parse import urlparse, quote
# Configure Logging
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO").upper()
@@ -44,14 +44,32 @@ def tosElement(tosdrId):
return ""
return f"[](https://tosdr.org/en/service/{tosdrId})"
-def statsElement(isOpenSource, isSecurityAudited, isAcceptsCrypto):
+def statsElement(app, categoryName, sectionName):
statsStr = ""
- if isOpenSource == True:
- statsStr += "📦 Open Source "
- if isSecurityAudited == True:
- statsStr += "🛡️ Security Audited "
- if isAcceptsCrypto == True:
- statsStr += "💰 Accepts Anonymous Payment "
+ if app.get('openSource') == True:
+ github = app.get('github')
+ if github:
+ link = f"https://github.com/{github}"
+ elif app.get('url'):
+ link = app.get('url')
+ else:
+ link = f"https://awesome-privacy.xyz/{slugify(categoryName)}/{slugify(sectionName)}/{slugify(app.get('name'))}"
+ statsStr += (
+ f"[]({link}) "
+ )
+ if app.get('securityAudited') == True:
+ statsStr += (
+ " "
+ )
+ if app.get('acceptsCrypto') == True:
+ statsStr += (
+ " "
+ )
return statsStr
def slugify(title):
@@ -63,6 +81,11 @@ def slugify(title):
title = title.replace('?', '')
return title
+def shieldsEncode(text):
+ if not text: return ''
+ text = text.strip().replace('-', '--').replace('_', '__').replace(' ', '_')
+ return quote(text, safe='_-.')
+
def awesomePrivacyReport(categoryName, sectionName, serviceName):
if not serviceName:
return ""
@@ -72,12 +95,74 @@ def awesomePrivacyReport(categoryName, sectionName, serviceName):
f"(https://awesome-privacy.xyz/{slugify(categoryName)}/{slugify(sectionName)}/{slugify(serviceName)})"
)
-def makeStatsCard():
- return (
- f"\t- Stats
\n\n"
- f""
- f"\n\n "
- )
+def playStoreBadge(name, androidApp):
+ if not androidApp: return ""
+ encoded = shieldsEncode(name)
+ return (
+ f"[]"
+ f"(https://play.google.com/store/apps/details?id={androidApp}) "
+ )
+
+def appStoreBadge(name, iosApp):
+ if not iosApp: return ""
+ encoded = shieldsEncode(name)
+ return (
+ f"[]"
+ f"({iosApp}) "
+ )
+
+def redditBadge(subreddit):
+ if not subreddit or not subreddit.strip(): return ""
+ sub = subreddit.strip()
+ return (
+ f"[]"
+ f"(https://reddit.com/r/{sub}) "
+ )
+
+def discordBadge(name, discordInvite):
+ if not discordInvite or not discordInvite.strip(): return ""
+ invite = discordInvite.strip()
+ encoded = shieldsEncode(name)
+ link = invite if invite.startswith('https://') else f"https://discord.gg/{invite}"
+ return (
+ f"[]"
+ f"({link}) "
+ )
+
+_MD_PATTERNS = [
+ re.compile(r'\[([^\]]*)\]\([^)]*\)'), # [text](url) — group 1 = visible text
+ re.compile(r'\*\*(.+?)\*\*'), # **bold**
+ re.compile(r'`([^`]+)`'), # `code`
+ re.compile(r'(?\n\t\tStats\n\n\t\t"
- f"{repoElement(app.get('github'))} "
- f"{tosElement(app.get('tosdrId'))} "
- f"{awesomePrivacyReport(category.get('name'), section.get('name'), app.get('name'))} \n"
- f"{statsElement(app.get('openSource'), app.get('securityAudited'), app.get('acceptsCrypto'))}˙ \n"
- f"\n\t\t\n"
- )
- if app.get('github') or app.get('tosdrId') else '')
+ f"({app.get('url')})** - {description}{ellipsis} \n"
)
+ badges = ' '.join(filter(None, [
+ repoElement(app.get('github')),
+ tosElement(app.get('tosdrId')),
+ awesomePrivacyReport(category.get('name'), section.get('name'), app.get('name')),
+ statsElement(app, category.get('name'), section.get('name')).rstrip(),
+ playStoreBadge(app.get('name'), app.get('androidApp')).rstrip(),
+ appStoreBadge(app.get('name'), app.get('iosApp')).rstrip(),
+ redditBadge(app.get('subreddit')).rstrip(),
+ discordBadge(app.get('name'), app.get('discordInvite')).rstrip(),
+ ]))
+ if badges:
+ markdown += (
+ f"\t- \n\t\tStats
\n\n\t\t"
+ f"{badges}ㅤ \n"
+ f"\n\t\t \n"
+ )
markdown += "\n"
# If word of warning exists, append it
if section.get('wordOfWarning'):
@@ -145,7 +241,7 @@ def makeAwesomePrivacy():
markdown += f"> - [{mention.get('name')}]({mention.get('url')})" + (
f" - {mention.get('description')}" if mention.get('description') else "\n"
)
- else:
+ else:
notable_mentions = section.get('notableMentions').replace('\n', '\n> ')
markdown += f"> {notable_mentions}"
@@ -170,7 +266,7 @@ def update_content_between_markers(content, start_marker, end_marker, new_conten
logger.info(f"Updating content between {start_marker} and {end_marker} markers...")
start_index = content.find(start_marker)
end_index = content.find(end_marker)
-
+
if start_index != -1 and end_index != -1:
before_section = content[:start_index + len(start_marker)]
after_section = content[end_index:]