1
0
mirror of https://github.com/privacyguides/privacyguides.org.git synced 2025-08-30 14:49:18 +00:00

feat!: Include ZIM files in releases (#3102)

This commit is contained in:
2025-08-27 17:30:25 -05:00
parent 575818a637
commit 86b9f63f37
20 changed files with 751 additions and 63 deletions

19
tools/archive-releases.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
set -euo pipefail
REPO="privacyguides/privacyguides.org"
BASE_DIR="releases"
mkdir -p "$BASE_DIR"
# Get all release tags using gh CLI
release_tags=$(gh release list -R "$REPO" --limit 1000 | awk '{print $1}')
for tag in $release_tags; do
target_dir="$BASE_DIR/$tag"
mkdir -p "$target_dir"
echo "Downloading assets for release: $tag"
gh release download "$tag" -R "$REPO" --dir "$target_dir"
done
echo "All releases downloaded."

View File

@@ -0,0 +1,64 @@
#!/bin/bash
# Script to find and delete unreferenced asset files
# This script searches through all HTML, CSS, and JavaScript files to see if asset files are referenced
set -e # Exit on any error
echo -e "Starting unreferenced asset cleanup..."
echo "Assets directory: $ASSETS_DIR"
echo "Search directory: $SEARCH_DIR"
echo ""
# Check if assets directory exists
if [ ! -d "$ASSETS_DIR" ]; then
echo -e "Error: Assets directory '$ASSETS_DIR' not found!"
exit 1
fi
# Find all asset files recursively
echo "Finding all asset files..."
ASSET_FILES=$(find "$ASSETS_DIR" -type f)
ASSET_COUNT=$(echo "$ASSET_FILES" | wc -l)
echo "Found $ASSET_COUNT asset files"
echo ""
# Find all HTML, CSS, and JavaScript files
echo "Finding all HTML, CSS, and JavaScript files..."
SEARCH_FILES=$(find "$SEARCH_DIR" \( -name "*.html" -o -name "*.css" -o -name "*.js" \) -type f)
SEARCH_COUNT=$(echo "$SEARCH_FILES" | wc -l)
echo "Found $SEARCH_COUNT HTML, CSS, and JavaScript files"
echo ""
# Process each asset file
echo "Checking each asset file for references..."
echo ""
while IFS= read -r asset_file; do
if [ -z "$asset_file" ]; then
continue
fi
# Get just the filename (without path)
asset_filename=$(basename "$asset_file")
# Search for this filename in all HTML, CSS, and JavaScript files
found_reference=false
while IFS= read -r search_file; do
if [ -z "$search_file" ]; then
continue
fi
# Simple string search for the filename in the file
if grep -q "$asset_filename" "$search_file" 2>/dev/null; then
found_reference=true
break
fi
done <<< "$SEARCH_FILES"
if [ "$found_reference" = false ]; then
echo -e "Unreferenced: $asset_file"
rm "$asset_file"
fi
done <<< "$ASSET_FILES"

102
tools/generate-members.py Normal file
View File

@@ -0,0 +1,102 @@
import requests
import os
GITHUB_API_URL = "https://api.github.com/graphql"
GITHUB_TOKEN = os.getenv("GH_TOKEN")
ORG_NAME = "privacyguides"
# Fetch members from the API
members_api_url = "https://discuss.privacyguides.net/g/members/members.json?offset=0&order=added_at&asc=true"
headers = {
"Api-Key": os.getenv("DISCOURSE_API_KEY"),
"Api-Username": "system"
}
members_response = requests.get(members_api_url, headers=headers)
members_data = members_response.json()
if 'members' not in members_data:
raise KeyError("Response JSON does not contain 'members' key")
members = members_data['members']
public_members_count = 0
private_members_count = 0
html_output = ""
for member in members:
flair_name = member.get('flair_name')
title = member.get('title')
if flair_name == "members" or title == "Member":
username = member['username']
avatar_template = member['avatar_template']
avatar_url = f"https://discuss.privacyguides.net{avatar_template.replace('{size}', '128')}"
profile_url = f"https://discuss.privacyguides.net/u/{username}"
html_output += f'<a href="{profile_url}" target="_blank" title="@{username}" class="mdx-donors__item"><img loading="lazy" src="{avatar_url}"></a>'
public_members_count += 1
# print(html_output)
query = """
{
organization(login: "%s") {
sponsorshipsAsMaintainer(first: 100) {
nodes {
sponsorEntity {
... on User {
login
avatarUrl
url
}
... on Organization {
login
avatarUrl
url
}
}
createdAt
}
}
}
}
""" % ORG_NAME
headers = {
"Authorization": f"Bearer {GITHUB_TOKEN}",
"Content-Type": "application/json"
}
response = requests.post(GITHUB_API_URL, json={'query': query}, headers=headers)
data = response.json()
if 'errors' in data:
raise Exception(f"GraphQL query failed with errors: {data['errors']}")
if 'data' not in data:
raise KeyError(f"Response JSON does not contain 'data' key: {data}")
sponsors = data['data']['organization']['sponsorshipsAsMaintainer']['nodes']
# Sort sponsors by the date they began their sponsorship
sponsors.sort(key=lambda x: x['createdAt'])
for sponsor in sponsors:
sponsor_entity = sponsor['sponsorEntity']
login = sponsor_entity['login']
avatar_url = sponsor_entity['avatarUrl']
url = sponsor_entity['url']
html_output += f'<a href="{url}" title="@{login}" rel="ugc nofollow" target="_blank" class="mdx-donors__item"><img loading="lazy" src="{avatar_url}&size=120"></a>'
# Fetch the number of active members from the Magic Grants API
magic_grants_url = "https://donate.magicgrants.org/api/active-members?fund=privacyguides"
magic_grants_response = requests.get(magic_grants_url)
magic_grants_data = magic_grants_response.json()
if 'members_count' not in magic_grants_data:
raise KeyError("Response JSON does not contain 'members_count' key")
private_members_count += magic_grants_data['members_count']
private_members_count -= public_members_count
# Append the count of private members
if private_members_count > 0:
html_output += f'<a href="https://donate.magicgrants.org/privacyguides" class="mdx-donors__item mdx-donors__item--private">+{private_members_count}</a>'
print(html_output)

91
tools/generate-topics.sh Executable file
View File

@@ -0,0 +1,91 @@
#!/bin/bash
DATE_CMD="date"
# Check if the script is running on macOS
if [[ "$OSTYPE" == "darwin"* ]]; then
DATE_CMD="gdate"
fi
# Defaults
source="https://discuss.privacyguides.net/top.json?period=weekly"
tag="top posts"
destination="./site/en/index.html"
count=3
for arg in "$@"
do
case $arg in
--source=*)
source="${arg#*=}"
shift
;;
--tag=*)
tag="${arg#*=}"
shift
;;
--destination=*)
destination="${arg#*=}"
shift
;;
--count=*)
count="${arg#*=}"
shift
;;
esac
done
# URL of the Discourse top.json
DISCOURSE_URL="$source"
# Fetch the JSON data
json_data="$(curl -s "$DISCOURSE_URL")"
# Extract the first 3 topics
topics=$(echo "$json_data" | jq -r ".topic_list.topics[:$count]")
users=$(echo "$json_data" | jq -r ".users")
# Generate HTML for the first 3 posts
html_output=""
for row in $(echo "${topics}" | jq -r '.[] | @base64'); do
_jq() {
echo "${row}" | base64 --decode | jq -r "${1}"
}
title="$(_jq '.title')"
id=$(_jq '.id')
like_count=$(_jq '.like_count')
reply_count=$(_jq '.posts_count')
views=$(_jq '.views')
author_id=$(_jq '.posters[0].user_id')
author_info=$(echo "${users}" | jq -r ".[] | select(.id==$author_id)")
author_username=$(echo "${author_info}" | jq -r ".username")
html_output+="<li class='discourse-topic'>"
html_output+="<p class='discourse-title'><a href='https://discuss.privacyguides.net/t/${id}'><strong>${title}</strong></a></p>"
html_output+="<hr>"
html_output+="<p class='discourse-author'>"
html_output+="<span class='discourse-author'>"
if [[ -z "$BUILD_OFFLINE" ]]; then
html_output+="<img src='https://forum-cdn.privacyguides.net/user_avatar/discuss.privacyguides.net/${author_username}/48/1.png' loading='lazy' aria-hidden='true' alt='${author_username}' width='20' height='20' class='middle'>"
fi
html_output+="<span> Posted by <em>$author_username</em></span>"
html_output+="</span>"
html_output+="</p>"
html_output+="<p class='discourse-data'>"
html_output+="<span class='twemoji'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><title>eye</title><path d='M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z' /></svg></span>"
html_output+="<span class='discourse-views'> ${views} </span>"
html_output+="<span class='twemoji pg-red'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><title>heart</title><path d='M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z' /></svg></span>"
html_output+="<span class='discourse-likes'> ${like_count} </span>"
html_output+="<span class='twemoji'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><title>reply</title><path d='M10,9V5L3,12L10,19V14.9C15,14.9 18.5,16.5 21,20C20,15 17,10 10,9Z' /></svg></span>"
html_output+="<span class='discourse-replies'> ${reply_count} </span>"
html_output+="</p>"
html_output+="</li>"
done
tempfile=$(mktemp)
echo "$html_output" > "$tempfile"
# Insert the HTML output between the comments in index.html
sed -i'.bak' "/<!-- start $tag -->/,/<!-- end $tag -->/{//!d;}; /<!-- start $tag -->/r $tempfile" "$destination"

View File

@@ -0,0 +1,20 @@
#!/bin/bash
set -euo pipefail
declare -A file_hashes
find . -type f | while read -r file; do
hash=$(sha256sum "$file" | awk '{print $1}')
if [[ -n "${file_hashes[$hash]+_}" ]]; then
# Duplicate found, replace with symlink to first copy
first="${file_hashes[$hash]}"
# Remove the duplicate file
rm "$file"
# Create symlink (relative path)
ln -s "$(realpath --relative-to="$(dirname "$file")" "$first")" "$file"
echo "Replaced duplicate: $file -> $first"
else
# First time seeing this hash
file_hashes[$hash]="$file"
fi
done