1 | import { getIfUpdate, UpdatedObject } from "@xmcl/net";
|
2 | import * as parser from "fast-html-parser";
|
3 | import { ForgeInstaller } from "./index";
|
4 |
|
5 | export namespace ForgeWebPage {
|
6 |
|
7 | export interface Download {
|
8 | md5: string;
|
9 | sha1: string;
|
10 | path: string;
|
11 | }
|
12 |
|
13 | |
14 |
|
15 |
|
16 | export function parse(content: string): ForgeWebPage {
|
17 | const dom = parser.parse(content);
|
18 | const selected = dom.querySelector(".elem-active");
|
19 | const mcversion = selected.text;
|
20 | return {
|
21 | timestamp: "",
|
22 | mcversion,
|
23 | versions: dom.querySelector(".download-list").querySelector("tbody").querySelectorAll("tr")
|
24 | .map((e) => {
|
25 | const links = e.querySelector(".download-links").childNodes
|
26 | .filter((elem) => elem.tagName === "li")
|
27 | .map((elem) => {
|
28 | elem = elem.removeWhitespace();
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | const tooltipInfo = elem.querySelector(".info-tooltip");
|
36 | const url = tooltipInfo.querySelector("a") || elem.querySelector("a");
|
37 |
|
38 | const href = url.attributes.href.trim();
|
39 | const matched = /forge-.+-.+-(\w+)\.\w+/.exec(href);
|
40 | let name = "", sha1 = "", md5 = "";
|
41 | if (matched) { name = matched[1]; }
|
42 | if (!name) {
|
43 | throw new Error(`Cannot determine name for forge url "${href}". Maybe the forge webisite changed?`);
|
44 | }
|
45 | try {
|
46 | md5 = tooltipInfo.childNodes[1].text.trim();
|
47 | sha1 = tooltipInfo.childNodes[4].text.trim();
|
48 | } catch {
|
49 | console.warn(`Error during fetching the sha1 and md5 for the forge "${href}". The result might be wrong.`);
|
50 | }
|
51 | const isSha1 = /\b([a-f0-9]{40})\b/i
|
52 | const isMd5 = /\b[a-f0-9]{32}\b/i;
|
53 | if (!isMd5.test(md5.trim())) {
|
54 | console.warn(`Illegal Md5 for "${href}": ${md5}`)
|
55 | md5 = "";
|
56 | }
|
57 | if (!isSha1.test(sha1.trim())) {
|
58 | console.warn(`Illegal Sha1 for "${href}": ${sha1}`)
|
59 | sha1 = "";
|
60 | }
|
61 | return {
|
62 | name,
|
63 | md5,
|
64 | sha1,
|
65 | path: href,
|
66 | };
|
67 | });
|
68 | const downloadVersionElem = e.querySelector(".download-version");
|
69 | let version;
|
70 | let type: ForgeWebPage.Version["type"] = "common";
|
71 | const icon = downloadVersionElem.querySelector("i");
|
72 | if (icon) {
|
73 | if (icon.classNames.indexOf("promo-recommended") !== -1) {
|
74 | type = "recommended";
|
75 | } else if (icon.classNames.indexOf("promo-latest") !== -1) {
|
76 | type = "latest";
|
77 | } else if (icon.classNames.indexOf("fa-bug") !== -1) {
|
78 | type = "buggy";
|
79 | }
|
80 | version = downloadVersionElem.firstChild.text.trim();
|
81 | } else {
|
82 | version = downloadVersionElem.text.trim();
|
83 | }
|
84 | const installer = links.find((l) => l.name === "installer");
|
85 | const universal = links.find((l) => l.name === "universal");
|
86 | const changelog = links.find((l) => l.name === "changelog");
|
87 | const installerWin = links.find((l) => l.name === "installer-win");
|
88 | const source = links.find((l) => l.name === "source");
|
89 | const launcher = links.find((l) => l.name === "launcher");
|
90 |
|
91 | const mdk = links.find((l) => l.name === "mdk");
|
92 |
|
93 | if (installer === undefined || universal === undefined) {
|
94 | throw new Error("Cannot parse forge web since it missing installer and universal jar info.");
|
95 | }
|
96 | const result = {
|
97 | version,
|
98 | "date": e.querySelector(".download-time").text.trim(),
|
99 | changelog,
|
100 | installer,
|
101 | mdk,
|
102 | universal,
|
103 | source,
|
104 | launcher,
|
105 | "installer-win": installerWin,
|
106 | "mcversion": mcversion,
|
107 | type,
|
108 | };
|
109 |
|
110 | return result;
|
111 | }),
|
112 | };
|
113 | }
|
114 |
|
115 | |
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | export function getWebPage(): Promise<ForgeWebPage | undefined>;
|
124 | |
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | export function getWebPage(option?: {
|
133 | mcversion?: string;
|
134 | }): Promise<ForgeWebPage | undefined>;
|
135 | |
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 | export function getWebPage(option?: {
|
144 | mcversion?: string;
|
145 | fallback?: ForgeWebPage;
|
146 | }): Promise<ForgeWebPage | undefined>;
|
147 | |
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | export function getWebPage(option?: {
|
156 | mcversion?: string;
|
157 | fallback: ForgeWebPage;
|
158 | }): Promise<ForgeWebPage>;
|
159 |
|
160 | |
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 | export async function getWebPage(option: {
|
169 | mcversion?: string,
|
170 | fallback?: ForgeWebPage,
|
171 | } = {}): Promise<ForgeWebPage | undefined> {
|
172 | const mcversion = option.mcversion || "";
|
173 | const url = mcversion === "" ? "http://files.minecraftforge.net/maven/net/minecraftforge/forge/index.html" : `http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_${mcversion}.html`;
|
174 | const page = await getIfUpdate(url, parse, option.fallback);
|
175 | return page;
|
176 | }
|
177 |
|
178 | |
179 |
|
180 |
|
181 | export interface Version extends ForgeInstaller.VersionMeta {
|
182 | |
183 |
|
184 |
|
185 | mcversion: string;
|
186 | |
187 |
|
188 |
|
189 | version: string;
|
190 | date: string;
|
191 | |
192 |
|
193 |
|
194 | changelog?: ForgeWebPage.Download;
|
195 | installer: ForgeWebPage.Download;
|
196 | mdk?: ForgeWebPage.Download;
|
197 | universal: ForgeWebPage.Download;
|
198 | source?: ForgeWebPage.Download;
|
199 | launcher?: ForgeWebPage.Download;
|
200 |
|
201 | |
202 |
|
203 |
|
204 | type: "buggy" | "recommended" | "common" | "latest";
|
205 | }
|
206 |
|
207 | export namespace Version {
|
208 | export function to(webPageVersion: ForgeWebPage.Version): ForgeInstaller.VersionMeta {
|
209 | return {
|
210 | universal: webPageVersion.universal,
|
211 | installer: webPageVersion.installer,
|
212 | mcversion: webPageVersion.mcversion,
|
213 | version: webPageVersion.version,
|
214 | };
|
215 | }
|
216 | }
|
217 | }
|
218 |
|
219 | declare module "./index" {
|
220 | export namespace VersionMeta {
|
221 | export function from(webPageVersion: ForgeWebPage.Version): ForgeInstaller.VersionMeta;
|
222 | }
|
223 | }
|
224 |
|
225 | (ForgeInstaller as any).VersionMeta = (ForgeInstaller as any).VersionMeta || {};
|
226 | (ForgeInstaller as any).VersionMeta.from = ForgeWebPage.Version.to;
|
227 |
|
228 | export interface ForgeWebPage extends UpdatedObject {
|
229 | versions: ForgeWebPage.Version[];
|
230 | mcversion: string;
|
231 | }
|
232 |
|
233 |
|
234 |
|