You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ytdl-android/scripts/fetch_translators.py

81 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Builds the translators list shown in the app from the public Weblate API.
Writes {"<lang>": [{"username": "...", "avatar": "<url>"}, ...], ...} to the given path.
Run by the "Update translators" workflow, which commits the result. On any error
(rate limit, network) it exits non-zero without touching the output file.
Usage: fetch_translators.py <output.json>
"""
import json
import sys
import time
import urllib.error
import urllib.request
from collections import defaultdict
BASE = "https://hosted.weblate.org"
PROJECT = "ytdlnis"
PAGE_SIZE = 1000
# 2 = translation changed, 5 = translation added, 7 = suggestion accepted
ACTIONS = (2, 5, 7)
IGNORED_USERS = {"anonymous"}
def get(url):
req = urllib.request.Request(url, headers={"User-Agent": "ytdlnis-ci", "Accept": "application/json"})
for attempt in range(3):
try:
with urllib.request.urlopen(req, timeout=60) as r:
return json.load(r)
except urllib.error.HTTPError as e:
if e.code == 429:
raise
if attempt == 2:
raise
except urllib.error.URLError:
if attempt == 2:
raise
time.sleep(2)
def collect(counts):
for action in ACTIONS:
url = f"{BASE}/api/projects/{PROJECT}/changes/?action={action}&page_size={PAGE_SIZE}"
while url:
page = get(url)
for change in page["results"]:
author = change.get("author")
translation = change.get("translation")
if not author or not translation:
continue
username = author.rstrip("/").rsplit("/", 1)[-1]
if username in IGNORED_USERS:
continue
lang = translation.rstrip("/").rsplit("/", 1)[-1]
counts[lang][username] += 1
url = page.get("next")
def main(out):
counts = defaultdict(lambda: defaultdict(int))
try:
collect(counts)
except Exception as e: # rate limit / network: don't overwrite the committed file with partial data
print(f"error: could not fetch translators: {e}", file=sys.stderr)
sys.exit(1)
result = {}
for lang in sorted(counts):
users = sorted(counts[lang].items(), key=lambda kv: (-kv[1], kv[0]))
result[lang] = [
{"username": u, "avatar": f"{BASE}/avatar/128/{u}.png"} for u, _ in users
]
with open(out, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=1)
print(f"wrote {sum(len(v) for v in result.values())} entries for {len(result)} languages")
if __name__ == "__main__":
main(sys.argv[1] if len(sys.argv) > 1 else "translators.json")