1"""Fetches my public repositories and downloads tagged versions."""
  2from datetime import datetime
  3import sys
  4import json
  5import requests
  6
  7USERNAME = "mitjafelicijan"
  8CACHE_BUSTER = int(datetime.now().timestamp())
  9DOUBLE_NL = "\n\n"
 10
 11headers = {
 12    "Accept": "application/vnd.github.v3+json"
 13}
 14
 15def generate_markdown_file(include_repositories):
 16    file = open("../content/pages/projects.github.md.part", "w")
 17
 18    file.write(DOUBLE_NL)
 19    file.write("# GitHub repositories")
 20    file.write(DOUBLE_NL)
 21
 22    file.write("<div class='project-list'>")
 23    file.write(DOUBLE_NL)
 24
 25    for repo in include_repositories:
 26        file.write(f"- [{repo['name']}](#{repo['name'].lower()}) \n")
 27
 28    file.write(DOUBLE_NL)
 29    file.write("</div>")
 30    file.write(DOUBLE_NL)
 31
 32    for repo in include_repositories:
 33        print(f"> {repo['name']}")
 34
 35        file.write(f"## {repo['name']}\n")
 36        file.write(f"{repo['description']}\n")
 37
 38        file.write(DOUBLE_NL)
 39        file.write("<div class='project-release'>")
 40        file.write(DOUBLE_NL)
 41        file.write("|Released|Description|Download|\n")
 42        file.write("|--------|-----------|--------|\n")
 43
 44        for release in repo['releases']:
 45            print(f"   - {release['name']} - {release['created_at']}")
 46            dt = datetime.strptime(release["created_at"], "%Y-%m-%dT%H:%M:%SZ")
 47            file.write(f"|{dt.strftime('%Y-%m-%d')}|{release['name']}| [{release['filename']}](/projects/{release['filename']}) |\n")
 48
 49        file.write(DOUBLE_NL)
 50        file.write("</div>")
 51        file.write(DOUBLE_NL)
 52
 53        file.write("<div class='github-link'>")
 54        file.write(DOUBLE_NL)
 55        file.write("![](/assets/general/github.svg)")
 56        file.write(f"[{USERNAME}/{repo['name']}](https://github.com/{USERNAME}/{repo['name']})")
 57        file.write(DOUBLE_NL)
 58        file.write("</div>")
 59        file.write(DOUBLE_NL)
 60
 61    # file.write(DOUBLE_NL)
 62    # file.write("<style>\n")
 63    # file.write(".project-release table tr td:last-child { text-align: right; }\n")
 64    # file.write(".project-release table tr th:last-child { text-align: right; }\n")
 65    # file.write(".project-list ul { column-count: 3; column-gap: 3em; }\n")
 66    # file.write(".github-link p { display: flex; align-items: center; gap: 0.3em; }\n")
 67    # file.write(".github-link p img { border: 0; padding: 0; height: 15px; }\n")
 68    # file.write("</style>")
 69    # file.write(DOUBLE_NL)
 70
 71    file.close()
 72
 73def download_tarball(url, filepath):
 74    with requests.get(url, stream=True, timeout=30) as response:
 75        response.raise_for_status()
 76
 77        with open(filepath, "wb") as file:
 78            for chunk in response.iter_content(chunk_size=8192):
 79                file.write(chunk)
 80
 81def assert_rate_limit(response):
 82    rate_limit_limit = int(response.headers.get("x-ratelimit-limit"))
 83    rate_limit_remaining = int(response.headers.get("x-ratelimit-remaining"))
 84    rate_limit_reset = int(response.headers.get("x-ratelimit-reset"))
 85    print(f"Rate limit: {rate_limit_remaining}/{rate_limit_limit}")
 86    print(f"Reset time: {datetime.fromtimestamp(rate_limit_reset)}")
 87
 88    if rate_limit_remaining == 0:
 89        sys.exit(1)
 90
 91def fetch_github_data():
 92    include_repositories = []
 93    print(headers)
 94    response = requests.get(f"https://api.github.com/users/{USERNAME}/repos?ts={CACHE_BUSTER}&per_page=100",
 95                            headers=headers,
 96                            timeout=10)
 97
 98    assert_rate_limit(response)
 99
100    if response.status_code == 200:
101        repos = response.json()
102        for repo in repos:
103            # Check if repository has "winc" topic. This means I want to include
104            # this repository on this page.
105            if "winc" in repo["topics"]:
106                include_repositories.append(repo)
107    else:
108        print(f"Failed to retrieve repositories: {response.status_code}")
109        sys.exit(1)
110
111    for repo in include_repositories:
112        print(f"Name: {repo['name']}, URL: {repo['html_url']}")
113
114        response = requests.get(f"https://api.github.com/repos/{USERNAME}/{repo['name']}/releases?ts={CACHE_BUSTER}",
115                                headers=headers,
116                                timeout=10)
117
118        assert_rate_limit(response)
119
120        if response.status_code == 200:
121            repo["releases"] = response.json()
122            for release in repo["releases"]:
123                release["filename"] = f"{repo['name']}-{release['tag_name']}.tar.gz"
124                print(f"  > {release['tag_name']}, {release['name']}, {release['filename']}")
125                download_tarball(release["tarball_url"], f"../static/projects/{release['filename']}")
126        
127    return include_repositories
128
129include_repositories = fetch_github_data()
130
131# with open("out.json", "w") as json_file:
132#     json.dump(include_repositories, json_file, indent=4)
133
134generate_markdown_file(include_repositories)
135
136# with open("out.json", "r") as fp:
137#     include_repositories = json.load(fp)
138#     generate_markdown_file(include_repositories)