Initial commit

master
Wynd 2025-08-01 20:28:32 +03:00
commit 6f8fd23f49
2 changed files with 193 additions and 0 deletions

3
.gitignore vendored 100644
View File

@ -0,0 +1,3 @@
.env
out/
.hurl/

190
curse-stats.py 100755
View File

@ -0,0 +1,190 @@
#!/bin/python3
import requests
import os
import pathlib
from enum import Enum
from argparse import ArgumentParser
from dotenv import load_dotenv
from tabulate import tabulate
from datetime import datetime, timedelta, timezone
class Mod:
def __init__(self, data):
self.id = data["id"]
self.name = data["name"]
self.downloads = data["downloadCount"]
self.date_created = data["dateCreated"]
year_created = ""
try:
year_created = datetime.strptime(
data["dateCreated"], "%Y-%m-%dT%H:%M:%S.%f%z"
).strftime("%Y")
except ValueError:
year_created = datetime.strptime(
data["dateCreated"], "%Y-%m-%dT%H:%M:%S%z"
).strftime("%Y")
self.year_created = year_created
self.date_modified = data["dateModified"]
try:
self.date_released = datetime.strptime(
data["dateReleased"], "%Y-%m-%dT%H:%M:%S.%f%z"
)
except ValueError:
self.date_released = datetime.strptime(
data["dateReleased"], "%Y-%m-%dT%H:%M:%S%z"
)
class FilterType(Enum):
LastYear = "last-year"
Downloads = "downloads"
class SortType(Enum):
Downloads = "downloads"
InvDownloads = "-downloads"
ReleaseYear = "release-year"
InvReleaseYear = "-release-year"
if __name__ == "__main__":
load_dotenv()
def clamp(val: int, smallest: int, largest: int) -> int:
return max(smallest, min(val, largest))
pathlib.Path("./out").mkdir(exist_ok=True)
parser = ArgumentParser()
parser.add_argument(
"-f",
"--filter",
help="Filters what mods are included",
type=FilterType,
required=False,
action="append",
nargs="+",
dest="filter",
)
parser.add_argument(
"-s",
"--sort",
help="Sorts the mods before putting them in a table",
type=SortType,
required=False,
action="append",
nargs="+",
dest="sort",
)
parser.add_argument(
"--page-size",
help="Entries per page",
type=int,
default=50,
required=False,
dest="page_size",
)
parser.add_argument(
"--max-index",
help="Max amount of entries fetched",
type=int,
default=10_000,
required=False,
dest="max_index",
)
args = parser.parse_args()
page_size = clamp(args.page_size, 10, 50)
# Merge all filters into 1 array regardless of the arg format
filters = []
for filter_list in args.filter:
for filter in filter_list:
filters.append(filter)
sorts = []
for sort_list in args.sort:
for sort_logic in sort_list:
sorts.append(sort_logic)
def sort_mod(mod: Mod, sorts: list[SortType]):
sorting = []
for sort in sorts:
if sort is SortType.Downloads:
sorting.append(mod.downloads)
elif sort is SortType.InvDownloads:
sorting.append(-mod.downloads)
elif sort is SortType.ReleaseYear:
sorting.append(mod.year_created)
elif sort is SortType.InvReleaseYear:
sorting.append(-int(mod.year_created))
return tuple(sorting)
PAGE_SIZE = page_size
MAX_INDEX = args.max_index
URL = "https://api.curseforge.com/v1/mods/search"
PARAMS = {
"gameId": "432", # minecraft
"classId": 6, # mods
"sortField": 6, # downloads
"sortOrder": "desc",
"pageSize": PAGE_SIZE,
"index": 0,
}
CURSE_API_TOKEN = os.environ["CURSE_API_TOKEN"]
HEADERS = {"x-api-key": CURSE_API_TOKEN}
all_mods = []
for i in range(0, MAX_INDEX, PAGE_SIZE):
PARAMS["index"] = i
r = requests.get(url=URL, params=PARAMS, headers=HEADERS)
try:
data = r.json()
except ValueError as err:
print(err)
break
# pagination = data['pagination']
data = data["data"]
for entry in data:
mod = Mod(entry)
# filter mods with under 1M downloads
if FilterType.Downloads in filters:
if mod.downloads < 1_000_000:
continue
# filter mods without a release in the past year
if FilterType.LastYear in filters:
past = datetime.now(timezone.utc) - timedelta(days=365)
if mod.date_released < past:
continue
all_mods.append(mod)
print(f"{i} / {MAX_INDEX}")
all_mods.sort(key=lambda m: sort_mod(m, sorts))
all_mods = map(
lambda m: [
m.name,
"{0:,d}".format(m.downloads),
m.date_created,
m.date_released,
],
all_mods,
)
table = tabulate(
all_mods,
headers=["Name", "Downloads", "Created Date", "Last Release Date"],
tablefmt="double_grid",
showindex=True,
)
# Write the above table in a file for logging with today's date as the file's name
with open("./out/mods", "w") as f:
f.write(table)