mirror of
https://git.bits.team/Bits/mod-manager.git
synced 2024-11-23 14:38:21 -05:00
Add Forgejo as a mod source
This commit is contained in:
parent
f7649e2aeb
commit
21691f37db
@ -19,6 +19,7 @@ import Mods from "./mods/mods.js";
|
||||
import {CurseforgeSource} from "./mods/sources/curseforge_source.js";
|
||||
import MinecraftUtils from "./util/minecraft_utils.js";
|
||||
import chalk from "chalk";
|
||||
import ForgejoSource from "./mods/sources/forgejo_source.js";
|
||||
|
||||
export default class ModManager {
|
||||
public static logger: Logger | null = null;
|
||||
@ -63,6 +64,7 @@ export default class ModManager {
|
||||
|
||||
Mods.registerSource(new ModrinthSource())
|
||||
Mods.registerSource(new CurseforgeSource(), "CURSEFORGE_API_KEY")
|
||||
Mods.registerSource(new ForgejoSource(), "FORGEJO_API_KEY")
|
||||
|
||||
this.program.showSuggestionAfterError();
|
||||
this.program.showHelpAfterError();
|
||||
|
157
src/mods/sources/forgejo_source.ts
Normal file
157
src/mods/sources/forgejo_source.ts
Normal file
@ -0,0 +1,157 @@
|
||||
import axios from "axios";
|
||||
import ModSource from "./mod_source.js";
|
||||
import Util from "../../util/util.js";
|
||||
import { ForgejoFile, ForgejoFiles, ForgejoPackage as ForgejoSearchResponse } from "../../types/forgejo.js";
|
||||
import { parse } from "properties-parser"
|
||||
import ModNotFoundError from "../../errors/mod_not_found_error.js";
|
||||
import MinecraftUtils from "../../util/minecraft_utils.js";
|
||||
import { format } from "util";
|
||||
import Mods from "../mods.js";
|
||||
import FileDownloader from "../../io/file_downloder.js";
|
||||
import DownloadError from "../../errors/download_error.js";
|
||||
|
||||
export default class ForgejoSource implements ModSource {
|
||||
private static readonly BASE_URL: string = "https://git.bits.team/api/v1";
|
||||
private static readonly SEARCH_URL: string = ForgejoSource.BASE_URL + "/packages/Bits"
|
||||
private static readonly VERSION_URL: string = ForgejoSource.BASE_URL + "/repos/%s/%s/media/gradle.properties"
|
||||
private static readonly REPO_URL: string = ForgejoSource.BASE_URL + "/repositories/%s"
|
||||
private static readonly FILES_URL: string = ForgejoSource.BASE_URL + "/packages/%s/%s/%s/%s/files"
|
||||
|
||||
private async findPackage(query: string, mcVersion: string): Promise<{package: ForgejoSearchResponse, project_id: string} | undefined> {
|
||||
let page = 1;
|
||||
let pagesLeft = true;
|
||||
while (pagesLeft) {
|
||||
pagesLeft = false
|
||||
|
||||
const params = {
|
||||
q: query,
|
||||
page
|
||||
}
|
||||
const response: ForgejoSearchResponse[] = await this.makeRequest(ForgejoSource.SEARCH_URL, params);
|
||||
|
||||
for (const mod of response) {
|
||||
const versionParams = {
|
||||
ref: mod.version
|
||||
}
|
||||
|
||||
const url = format(ForgejoSource.VERSION_URL, mod.owner.username, mod.repository.name)
|
||||
|
||||
const versionResponse = await this.makeRequest(url, versionParams).catch(_ => "");
|
||||
const ver = parse(versionResponse)
|
||||
|
||||
if (ver["minecraft_version"] == mcVersion) {
|
||||
return {
|
||||
package: mod,
|
||||
project_id: mod.repository.id.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Util.isArrayEmpty(response)) {
|
||||
pagesLeft = true;
|
||||
}
|
||||
|
||||
page++
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async search(query: string = "BitsVanilla"): Promise<string> {
|
||||
const mcVersion = await MinecraftUtils.getCurrentMinecraftVersion();
|
||||
|
||||
let mod = await this.findPackage(query, mcVersion);
|
||||
|
||||
if (!mod) {
|
||||
throw new ModNotFoundError(`Mod ${query} could not be found on Forgejo`)
|
||||
}
|
||||
|
||||
return mod.project_id;
|
||||
}
|
||||
async install(version: Version, essential: boolean): Promise<void> {
|
||||
try {
|
||||
if (Mods.isModInstalled(version.modId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await FileDownloader.downloadMod(version)
|
||||
|
||||
const mod = {
|
||||
name: await this.getProjectName(version.modId),
|
||||
id: version.modId,
|
||||
fileName: version.fileName,
|
||||
version: version.versionNumber,
|
||||
source: this.getSourceName(),
|
||||
essential: essential,
|
||||
dependencies: []
|
||||
}
|
||||
|
||||
Mods.trackMod(mod)
|
||||
} catch (e) {
|
||||
throw new DownloadError(`An error occured downloading mod with id ${version.modId} from ${this.getSourceName()}`)
|
||||
}
|
||||
}
|
||||
getSourceName(): string {
|
||||
return "Forgejo";
|
||||
}
|
||||
async getProjectName(id: string): Promise<string> {
|
||||
const response = await this.makeRequest(format(ForgejoSource.REPO_URL, id))
|
||||
return response.name;
|
||||
}
|
||||
async getLatestVersion(id: string = "34", mcVersion: string = "24w13a"): Promise<Version> {
|
||||
const projectName = await this.getProjectName(id)
|
||||
|
||||
const mod = await this.findPackage(projectName, mcVersion)
|
||||
|
||||
if (!mod) {
|
||||
throw new ModNotFoundError(`Mod with id ${id} has no available versions on ${this.getSourceName()} for Minecraft version ${mcVersion}`);
|
||||
}
|
||||
|
||||
let filesUrl = format(ForgejoSource.FILES_URL, mod.package.owner.username, mod.package.type, mod.package.name, mod.package.version)
|
||||
|
||||
let filesResponse: ForgejoFiles = await this.makeRequest(filesUrl);
|
||||
|
||||
if (Util.isArrayEmpty(filesResponse)) {
|
||||
throw new ModNotFoundError(`Mod ${mod.package.name} has no files on Forgejo`)
|
||||
}
|
||||
|
||||
let latestFile: ForgejoFile | undefined = undefined;
|
||||
for (const file of filesResponse) {
|
||||
if (file.name.endsWith(".jar")) {
|
||||
latestFile = file
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!latestFile) {
|
||||
throw new ModNotFoundError(`Mod ${mod.package.name} has no jar files on Forgejo`)
|
||||
}
|
||||
|
||||
const downloadUrl = mod.package.html_url + `/files/${latestFile.id}`
|
||||
|
||||
const version = {
|
||||
modId: mod.project_id,
|
||||
versionNumber: mod.package.version,
|
||||
fileName: latestFile.name,
|
||||
url: downloadUrl,
|
||||
dependencies: [],
|
||||
checksum: latestFile.sha1
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
private async makeRequest(url: string, params?: object) {
|
||||
if (process.env.FORGEJO_API_KEY == undefined) {
|
||||
throw new Error("Attempted Forgejo api calls with undefined api key environment variable (FORGEJO_API_KEY)")
|
||||
}
|
||||
|
||||
params = Object.assign({}, {"access_token": process.env.FORGEJO_API_KEY}, params)
|
||||
|
||||
const response = await axios.get(url, {
|
||||
params
|
||||
})
|
||||
|
||||
return await response.data;
|
||||
}
|
||||
}
|
165
src/types/forgejo.d.ts
vendored
Normal file
165
src/types/forgejo.d.ts
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
export interface ForgejoPackage {
|
||||
id: number
|
||||
owner: Owner
|
||||
repository: Repository
|
||||
creator: Creator
|
||||
type: string
|
||||
name: string
|
||||
version: string
|
||||
html_url: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface Owner {
|
||||
id: number
|
||||
login: string
|
||||
login_name: string
|
||||
full_name: string
|
||||
email: string
|
||||
avatar_url: string
|
||||
language: string
|
||||
is_admin: boolean
|
||||
last_login: string
|
||||
created: string
|
||||
restricted: boolean
|
||||
active: boolean
|
||||
prohibit_login: boolean
|
||||
location: string
|
||||
website: string
|
||||
description: string
|
||||
visibility: string
|
||||
followers_count: number
|
||||
following_count: number
|
||||
starred_repos_count: number
|
||||
username: string
|
||||
}
|
||||
|
||||
export interface Repository {
|
||||
id: number
|
||||
owner: Owner2
|
||||
name: string
|
||||
full_name: string
|
||||
description: string
|
||||
empty: boolean
|
||||
private: boolean
|
||||
fork: boolean
|
||||
template: boolean
|
||||
parent: any
|
||||
mirror: boolean
|
||||
size: number
|
||||
language: string
|
||||
languages_url: string
|
||||
html_url: string
|
||||
url: string
|
||||
link: string
|
||||
ssh_url: string
|
||||
clone_url: string
|
||||
original_url: string
|
||||
website: string
|
||||
stars_count: number
|
||||
forks_count: number
|
||||
watchers_count: number
|
||||
open_issues_count: number
|
||||
open_pr_counter: number
|
||||
release_counter: number
|
||||
default_branch: string
|
||||
archived: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
archived_at: string
|
||||
permissions: Permissions
|
||||
has_issues: boolean
|
||||
internal_tracker: InternalTracker
|
||||
has_wiki: boolean
|
||||
has_pull_requests: boolean
|
||||
has_projects: boolean
|
||||
has_releases: boolean
|
||||
has_packages: boolean
|
||||
has_actions: boolean
|
||||
ignore_whitespace_conflicts: boolean
|
||||
allow_merge_commits: boolean
|
||||
allow_rebase: boolean
|
||||
allow_rebase_explicit: boolean
|
||||
allow_squash_merge: boolean
|
||||
allow_rebase_update: boolean
|
||||
default_delete_branch_after_merge: boolean
|
||||
default_merge_style: string
|
||||
default_allow_maintainer_edit: boolean
|
||||
avatar_url: string
|
||||
internal: boolean
|
||||
mirror_interval: string
|
||||
mirror_updated: string
|
||||
repo_transfer: any
|
||||
}
|
||||
|
||||
export interface Owner2 {
|
||||
id: number
|
||||
login: string
|
||||
login_name: string
|
||||
full_name: string
|
||||
email: string
|
||||
avatar_url: string
|
||||
language: string
|
||||
is_admin: boolean
|
||||
last_login: string
|
||||
created: string
|
||||
restricted: boolean
|
||||
active: boolean
|
||||
prohibit_login: boolean
|
||||
location: string
|
||||
website: string
|
||||
description: string
|
||||
visibility: string
|
||||
followers_count: number
|
||||
following_count: number
|
||||
starred_repos_count: number
|
||||
username: string
|
||||
}
|
||||
|
||||
export interface Permissions {
|
||||
admin: boolean
|
||||
push: boolean
|
||||
pull: boolean
|
||||
}
|
||||
|
||||
export interface InternalTracker {
|
||||
enable_time_tracker: boolean
|
||||
allow_only_contributors_to_track_time: boolean
|
||||
enable_issue_dependencies: boolean
|
||||
}
|
||||
|
||||
export interface Creator {
|
||||
id: number
|
||||
login: string
|
||||
login_name: string
|
||||
full_name: string
|
||||
email: string
|
||||
avatar_url: string
|
||||
language: string
|
||||
is_admin: boolean
|
||||
last_login: string
|
||||
created: string
|
||||
restricted: boolean
|
||||
active: boolean
|
||||
prohibit_login: boolean
|
||||
location: string
|
||||
website: string
|
||||
description: string
|
||||
visibility: string
|
||||
followers_count: number
|
||||
following_count: number
|
||||
starred_repos_count: number
|
||||
username: string
|
||||
}
|
||||
|
||||
export type ForgejoFiles = ForgejoFile[]
|
||||
|
||||
export interface ForgejoFile {
|
||||
id: number
|
||||
Size: number
|
||||
name: string
|
||||
md5: string
|
||||
sha1: string
|
||||
sha256: string
|
||||
sha512: string
|
||||
}
|
Loading…
Reference in New Issue
Block a user