Initial commit
commit
6f8fd23f49
|
@ -0,0 +1,3 @@
|
|||
.env
|
||||
out/
|
||||
.hurl/
|
|
@ -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)
|
Loading…
Reference in New Issue