@piyoraik/ffxiv-lodestone-character-lookup 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/data/high_end_achievements_ja.json +18 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lodestone.d.ts +23 -0
- package/dist/lodestone.d.ts.map +1 -0
- package/dist/lodestone.js +111 -0
- package/dist/lodestone.js.map +1 -0
- package/dist/lodestoneAchievements.d.ts +76 -0
- package/dist/lodestoneAchievements.d.ts.map +1 -0
- package/dist/lodestoneAchievements.js +193 -0
- package/dist/lodestoneAchievements.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @piyoraik/ffxiv-lodestone-character-lookup
|
|
2
|
+
|
|
3
|
+
FFXIV の Lodestone(キャラクター検索→キャラクターURL取得・高難度アチーブメント判定)を扱う共通ライブラリです。
|
|
4
|
+
|
|
5
|
+
## インストール
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
yarn add @piyoraik/ffxiv-lodestone-character-lookup
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使い方(例)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import {
|
|
15
|
+
parseCreator,
|
|
16
|
+
buildLodestoneSearchUrl,
|
|
17
|
+
fetchTopCharacterUrl,
|
|
18
|
+
buildAchievementCategoryUrl,
|
|
19
|
+
fetchAchievementCategoryHtml,
|
|
20
|
+
parseUltimateClearsFromAchievementHtml
|
|
21
|
+
} from "@piyoraik/ffxiv-lodestone-character-lookup";
|
|
22
|
+
|
|
23
|
+
const creator = parseCreator("Hoge Fuga @ Unicorn");
|
|
24
|
+
if (!creator) throw new Error("invalid creator");
|
|
25
|
+
|
|
26
|
+
const searchUrl = buildLodestoneSearchUrl(creator);
|
|
27
|
+
const characterUrl = await fetchTopCharacterUrl(searchUrl);
|
|
28
|
+
if (!characterUrl) throw new Error("character not found");
|
|
29
|
+
|
|
30
|
+
const achievementUrl = buildAchievementCategoryUrl(characterUrl);
|
|
31
|
+
if (!achievementUrl) throw new Error("achievement url not built");
|
|
32
|
+
|
|
33
|
+
const html = await fetchAchievementCategoryHtml(achievementUrl);
|
|
34
|
+
const result = parseUltimateClearsFromAchievementHtml(html);
|
|
35
|
+
console.log(result);
|
|
36
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"achievements": [
|
|
4
|
+
{ "name": "絶バハムートを狩りし者", "short": "絶バハ", "group": "ultimate" },
|
|
5
|
+
{ "name": "絶アルテマウェポンを破壊せし者", "short": "絶テマ", "group": "ultimate" },
|
|
6
|
+
{ "name": "絶アレキサンダーを破壊せし者", "short": "絶アレキ", "group": "ultimate" },
|
|
7
|
+
{ "name": "絶竜詩戦争を平定せし者", "short": "絶竜詩", "group": "ultimate" },
|
|
8
|
+
{ "name": "絶オメガ検証戦を完遂せし者", "short": "絶オメガ", "group": "ultimate" },
|
|
9
|
+
{ "name": "絶もうひとつの未来を見届けし者", "short": "絶エデン", "group": "ultimate" },
|
|
10
|
+
|
|
11
|
+
{ "name": "万魔殿の辺獄を完全制覇せし者:ランク1", "short": "【パンデモ】辺獄", "group": "savage" },
|
|
12
|
+
{ "name": "万魔殿の煉獄を完全制覇せし者:ランク1", "short": "【パンデモ】煉獄", "group": "savage" },
|
|
13
|
+
{ "name": "万魔殿の天獄を完全制覇せし者:ランク1", "short": "【パンデモ】天獄", "group": "savage" },
|
|
14
|
+
{ "name": "アルカディアのライトヘビー級を制覇せし者:ランク1", "short": "【アルカディア】ライトヘビー", "group": "savage" },
|
|
15
|
+
{ "name": "アルカディアのクルーザー級を完全制覇せし者:ランク1", "short": "【アルカディア】クルーザー", "group": "savage" },
|
|
16
|
+
{ "name": "アルカディアのヘビー級を完全制覇せし者:ランク1", "short": "【アルカディア】ヘビー", "group": "savage" }
|
|
17
|
+
]
|
|
18
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./lodestone"), exports);
|
|
18
|
+
__exportStar(require("./lodestoneAchievements"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,0DAAwC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type CreatorInfo = {
|
|
2
|
+
name: string;
|
|
3
|
+
world: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* `募集者: キャラクター名 @ サーバー名` 形式の文字列から、名前/ワールドを取り出します。
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseCreator(creator: string): CreatorInfo | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Lodestone のキャラクター検索URLを生成します。
|
|
11
|
+
* 例:
|
|
12
|
+
* `https://jp.finalfantasyxiv.com/lodestone/character/?q=Noah+Stella&worldname=Asura&...`
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildLodestoneSearchUrl(info: CreatorInfo): string;
|
|
15
|
+
/**
|
|
16
|
+
* キャラクター検索結果HTMLから、先頭に表示されるキャラクターURLを取得します。
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseTopCharacterUrlFromSearchHtml(html: string): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Lodestone のキャラクター検索を行い、先頭にヒットしたキャラクターURLを返します。
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchTopCharacterUrl(searchUrl: string): Promise<string | undefined>;
|
|
23
|
+
//# sourceMappingURL=lodestone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lodestone.d.ts","sourceRoot":"","sources":["../src/lodestone.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAYrE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAsBjE;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKnF;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAYzF"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.parseCreator = parseCreator;
|
|
40
|
+
exports.buildLodestoneSearchUrl = buildLodestoneSearchUrl;
|
|
41
|
+
exports.parseTopCharacterUrlFromSearchHtml = parseTopCharacterUrlFromSearchHtml;
|
|
42
|
+
exports.fetchTopCharacterUrl = fetchTopCharacterUrl;
|
|
43
|
+
const axios_1 = __importDefault(require("axios"));
|
|
44
|
+
const cheerio = __importStar(require("cheerio"));
|
|
45
|
+
const LODESTONE_BASE_URL = "https://jp.finalfantasyxiv.com";
|
|
46
|
+
/**
|
|
47
|
+
* `募集者: キャラクター名 @ サーバー名` 形式の文字列から、名前/ワールドを取り出します。
|
|
48
|
+
*/
|
|
49
|
+
function parseCreator(creator) {
|
|
50
|
+
const raw = creator.trim();
|
|
51
|
+
if (!raw)
|
|
52
|
+
return undefined;
|
|
53
|
+
const at = raw.lastIndexOf("@");
|
|
54
|
+
if (at === -1)
|
|
55
|
+
return undefined;
|
|
56
|
+
const name = raw.slice(0, at).trim();
|
|
57
|
+
const world = raw.slice(at + 1).trim();
|
|
58
|
+
if (!name || !world)
|
|
59
|
+
return undefined;
|
|
60
|
+
return { name, world };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Lodestone のキャラクター検索URLを生成します。
|
|
64
|
+
* 例:
|
|
65
|
+
* `https://jp.finalfantasyxiv.com/lodestone/character/?q=Noah+Stella&worldname=Asura&...`
|
|
66
|
+
*/
|
|
67
|
+
function buildLodestoneSearchUrl(info) {
|
|
68
|
+
const url = new URL("/lodestone/character/", LODESTONE_BASE_URL);
|
|
69
|
+
const params = url.searchParams;
|
|
70
|
+
params.set("q", info.name);
|
|
71
|
+
params.set("worldname", info.world);
|
|
72
|
+
params.set("classjob", "");
|
|
73
|
+
params.set("race_tribe", "");
|
|
74
|
+
// Lodestone の検索フォームが投げるパラメータに寄せています。
|
|
75
|
+
params.append("gcid", "1");
|
|
76
|
+
params.append("gcid", "2");
|
|
77
|
+
params.append("gcid", "3");
|
|
78
|
+
params.append("gcid", "0");
|
|
79
|
+
params.append("blog_lang", "ja");
|
|
80
|
+
params.append("blog_lang", "en");
|
|
81
|
+
params.append("blog_lang", "de");
|
|
82
|
+
params.append("blog_lang", "fr");
|
|
83
|
+
params.set("order", "");
|
|
84
|
+
return url.toString();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* キャラクター検索結果HTMLから、先頭に表示されるキャラクターURLを取得します。
|
|
88
|
+
*/
|
|
89
|
+
function parseTopCharacterUrlFromSearchHtml(html) {
|
|
90
|
+
const $ = cheerio.load(html);
|
|
91
|
+
const href = $("a.entry__link").first().attr("href");
|
|
92
|
+
if (!href)
|
|
93
|
+
return undefined;
|
|
94
|
+
return new URL(href, LODESTONE_BASE_URL).toString();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Lodestone のキャラクター検索を行い、先頭にヒットしたキャラクターURLを返します。
|
|
98
|
+
*/
|
|
99
|
+
async function fetchTopCharacterUrl(searchUrl) {
|
|
100
|
+
const response = await axios_1.default.get(searchUrl, {
|
|
101
|
+
responseType: "text",
|
|
102
|
+
headers: {
|
|
103
|
+
Accept: "text/html,application/xhtml+xml",
|
|
104
|
+
"Accept-Language": "ja,en;q=0.8",
|
|
105
|
+
"User-Agent": "ffxiv-lodestone-character-lookup/0.1 (+https://jp.finalfantasyxiv.com)"
|
|
106
|
+
},
|
|
107
|
+
timeout: 30_000
|
|
108
|
+
});
|
|
109
|
+
return parseTopCharacterUrlFromSearchHtml(response.data);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=lodestone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lodestone.js","sourceRoot":"","sources":["../src/lodestone.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 高難度(絶/零式)アチーブの正式名と表示用略称の定義(SSOT)。
|
|
3
|
+
*
|
|
4
|
+
* 定義は `high_end_achievements_ja.json` を同梱して読み取ります。
|
|
5
|
+
*/
|
|
6
|
+
export type HighEndAchievementGroup = "ultimate" | "savage";
|
|
7
|
+
export type HighEndAchievementDefinition = {
|
|
8
|
+
name: string;
|
|
9
|
+
short: string;
|
|
10
|
+
group: HighEndAchievementGroup;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 高難度アチーブ定義を取得します。
|
|
14
|
+
*/
|
|
15
|
+
export declare function getHighEndAchievements(): HighEndAchievementDefinition[];
|
|
16
|
+
export type HighEndAchievementName = string;
|
|
17
|
+
/**
|
|
18
|
+
* 互換用: 旧型名(`UltimateAchievementName`)。
|
|
19
|
+
*/
|
|
20
|
+
export type UltimateAchievementName = HighEndAchievementName;
|
|
21
|
+
/**
|
|
22
|
+
* 互換用: 旧API名(`getUltimateAchievements`)。
|
|
23
|
+
*/
|
|
24
|
+
export declare function getUltimateAchievements(): HighEndAchievementDefinition[];
|
|
25
|
+
/**
|
|
26
|
+
* 正式名 → 略称のルックアップを返します。
|
|
27
|
+
*/
|
|
28
|
+
export declare function getHighEndAchievementShortMap(): Map<HighEndAchievementName, string>;
|
|
29
|
+
/**
|
|
30
|
+
* 互換用: 旧API名(`getUltimateAchievementShortMap`)。
|
|
31
|
+
*/
|
|
32
|
+
export declare function getUltimateAchievementShortMap(): Map<HighEndAchievementName, string>;
|
|
33
|
+
/**
|
|
34
|
+
* 正式名 → 種別(絶/零式)のルックアップを返します。
|
|
35
|
+
*/
|
|
36
|
+
export declare function getHighEndAchievementGroupMap(): Map<HighEndAchievementName, HighEndAchievementGroup>;
|
|
37
|
+
/**
|
|
38
|
+
* 互換用: 旧API名(`getUltimateAchievementGroupMap`)。
|
|
39
|
+
*/
|
|
40
|
+
export declare function getUltimateAchievementGroupMap(): Map<HighEndAchievementName, HighEndAchievementGroup>;
|
|
41
|
+
/**
|
|
42
|
+
* キャラクターURL(例: `https://.../lodestone/character/12345/`)から characterId を抽出します。
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseCharacterIdFromUrl(characterUrl: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Lodestone のアチーブメント一覧URL(カテゴリ指定)を生成します。
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildHighEndAchievementCategoryUrl(characterUrl: string): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* 互換用: 旧API名(`buildAchievementCategoryUrl`)。
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildAchievementCategoryUrl(characterUrl: string): string | undefined;
|
|
53
|
+
export type HighEndAchievementParseResult = {
|
|
54
|
+
status: "ok" | "private_or_unavailable";
|
|
55
|
+
clears: string[];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 互換用: 旧型名(`UltimateAchievementParseResult`)。
|
|
59
|
+
*/
|
|
60
|
+
export type UltimateAchievementParseResult = HighEndAchievementParseResult;
|
|
61
|
+
/**
|
|
62
|
+
* アチーブメント一覧HTMLから、指定した高難度(絶/零式)アチーブの達成状況を判定します。
|
|
63
|
+
*
|
|
64
|
+
* 判定方法:
|
|
65
|
+
* - 対象の `<li class="entry">` 内に `time.entry__activity__time` が存在するか(=日付が入る)
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseHighEndClearsFromAchievementHtml(html: string): HighEndAchievementParseResult;
|
|
68
|
+
/**
|
|
69
|
+
* 互換用: 旧API名(`parseUltimateClearsFromAchievementHtml`)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function parseUltimateClearsFromAchievementHtml(html: string): HighEndAchievementParseResult;
|
|
72
|
+
/**
|
|
73
|
+
* Lodestone のアチーブメント一覧ページを取得します。
|
|
74
|
+
*/
|
|
75
|
+
export declare function fetchAchievementCategoryHtml(url: string): Promise<string>;
|
|
76
|
+
//# sourceMappingURL=lodestoneAchievements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lodestoneAchievements.d.ts","sourceRoot":"","sources":["../src/lodestoneAchievements.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE5D,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,uBAAuB,CAAC;CAChC,CAAC;AAoBF;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,4BAA4B,EAAE,CAEvE;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAE7D;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,4BAA4B,EAAE,CAExE;AAED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAMnF;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAEpF;AAED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,GAAG,CAAC,sBAAsB,EAAE,uBAAuB,CAAC,CAMpG;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,GAAG,CAAC,sBAAsB,EAAE,uBAAuB,CAAC,CAErG;AAQD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGhF;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO3F;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpF;AAED,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,IAAI,GAAG,wBAAwB,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,6BAA6B,CAAC;AAE3E;;;;;GAKG;AACH,wBAAgB,qCAAqC,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAqBjG;AAED;;GAEG;AACH,wBAAgB,sCAAsC,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAElG;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW/E"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.getHighEndAchievements = getHighEndAchievements;
|
|
40
|
+
exports.getUltimateAchievements = getUltimateAchievements;
|
|
41
|
+
exports.getHighEndAchievementShortMap = getHighEndAchievementShortMap;
|
|
42
|
+
exports.getUltimateAchievementShortMap = getUltimateAchievementShortMap;
|
|
43
|
+
exports.getHighEndAchievementGroupMap = getHighEndAchievementGroupMap;
|
|
44
|
+
exports.getUltimateAchievementGroupMap = getUltimateAchievementGroupMap;
|
|
45
|
+
exports.parseCharacterIdFromUrl = parseCharacterIdFromUrl;
|
|
46
|
+
exports.buildHighEndAchievementCategoryUrl = buildHighEndAchievementCategoryUrl;
|
|
47
|
+
exports.buildAchievementCategoryUrl = buildAchievementCategoryUrl;
|
|
48
|
+
exports.parseHighEndClearsFromAchievementHtml = parseHighEndClearsFromAchievementHtml;
|
|
49
|
+
exports.parseUltimateClearsFromAchievementHtml = parseUltimateClearsFromAchievementHtml;
|
|
50
|
+
exports.fetchAchievementCategoryHtml = fetchAchievementCategoryHtml;
|
|
51
|
+
const axios_1 = __importDefault(require("axios"));
|
|
52
|
+
const cheerio = __importStar(require("cheerio"));
|
|
53
|
+
const node_fs_1 = require("node:fs");
|
|
54
|
+
const node_path_1 = require("node:path");
|
|
55
|
+
const LODESTONE_BASE_URL = "https://jp.finalfantasyxiv.com";
|
|
56
|
+
const HIGH_END_CATEGORY_ID = 4;
|
|
57
|
+
const DEFINITIONS_FILE = (0, node_path_1.resolve)(__dirname, "data", "high_end_achievements_ja.json");
|
|
58
|
+
let cachedDefinitions;
|
|
59
|
+
let cachedShortMap;
|
|
60
|
+
let cachedGroupMap;
|
|
61
|
+
let cachedNameSet;
|
|
62
|
+
function loadDefinitions() {
|
|
63
|
+
if (cachedDefinitions)
|
|
64
|
+
return cachedDefinitions;
|
|
65
|
+
const rawText = (0, node_fs_1.readFileSync)(DEFINITIONS_FILE, "utf8");
|
|
66
|
+
const raw = JSON.parse(rawText);
|
|
67
|
+
cachedDefinitions = raw.achievements ?? [];
|
|
68
|
+
return cachedDefinitions;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 高難度アチーブ定義を取得します。
|
|
72
|
+
*/
|
|
73
|
+
function getHighEndAchievements() {
|
|
74
|
+
return loadDefinitions();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 互換用: 旧API名(`getUltimateAchievements`)。
|
|
78
|
+
*/
|
|
79
|
+
function getUltimateAchievements() {
|
|
80
|
+
return getHighEndAchievements();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 正式名 → 略称のルックアップを返します。
|
|
84
|
+
*/
|
|
85
|
+
function getHighEndAchievementShortMap() {
|
|
86
|
+
if (cachedShortMap)
|
|
87
|
+
return cachedShortMap;
|
|
88
|
+
const map = new Map();
|
|
89
|
+
for (const a of loadDefinitions())
|
|
90
|
+
map.set(a.name, a.short);
|
|
91
|
+
cachedShortMap = map;
|
|
92
|
+
return map;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 互換用: 旧API名(`getUltimateAchievementShortMap`)。
|
|
96
|
+
*/
|
|
97
|
+
function getUltimateAchievementShortMap() {
|
|
98
|
+
return getHighEndAchievementShortMap();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 正式名 → 種別(絶/零式)のルックアップを返します。
|
|
102
|
+
*/
|
|
103
|
+
function getHighEndAchievementGroupMap() {
|
|
104
|
+
if (cachedGroupMap)
|
|
105
|
+
return cachedGroupMap;
|
|
106
|
+
const map = new Map();
|
|
107
|
+
for (const a of loadDefinitions())
|
|
108
|
+
map.set(a.name, a.group);
|
|
109
|
+
cachedGroupMap = map;
|
|
110
|
+
return map;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 互換用: 旧API名(`getUltimateAchievementGroupMap`)。
|
|
114
|
+
*/
|
|
115
|
+
function getUltimateAchievementGroupMap() {
|
|
116
|
+
return getHighEndAchievementGroupMap();
|
|
117
|
+
}
|
|
118
|
+
function getHighEndAchievementNameSet() {
|
|
119
|
+
if (cachedNameSet)
|
|
120
|
+
return cachedNameSet;
|
|
121
|
+
cachedNameSet = new Set(loadDefinitions().map((a) => a.name));
|
|
122
|
+
return cachedNameSet;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* キャラクターURL(例: `https://.../lodestone/character/12345/`)から characterId を抽出します。
|
|
126
|
+
*/
|
|
127
|
+
function parseCharacterIdFromUrl(characterUrl) {
|
|
128
|
+
const match = characterUrl.match(/\/lodestone\/character\/(\d+)\//);
|
|
129
|
+
return match?.[1];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Lodestone のアチーブメント一覧URL(カテゴリ指定)を生成します。
|
|
133
|
+
*/
|
|
134
|
+
function buildHighEndAchievementCategoryUrl(characterUrl) {
|
|
135
|
+
const characterId = parseCharacterIdFromUrl(characterUrl);
|
|
136
|
+
if (!characterId)
|
|
137
|
+
return undefined;
|
|
138
|
+
return new URL(`/lodestone/character/${characterId}/achievement/category/${HIGH_END_CATEGORY_ID}/#anchor_achievement`, LODESTONE_BASE_URL).toString();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 互換用: 旧API名(`buildAchievementCategoryUrl`)。
|
|
142
|
+
*/
|
|
143
|
+
function buildAchievementCategoryUrl(characterUrl) {
|
|
144
|
+
return buildHighEndAchievementCategoryUrl(characterUrl);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* アチーブメント一覧HTMLから、指定した高難度(絶/零式)アチーブの達成状況を判定します。
|
|
148
|
+
*
|
|
149
|
+
* 判定方法:
|
|
150
|
+
* - 対象の `<li class="entry">` 内に `time.entry__activity__time` が存在するか(=日付が入る)
|
|
151
|
+
*/
|
|
152
|
+
function parseHighEndClearsFromAchievementHtml(html) {
|
|
153
|
+
const $ = cheerio.load(html);
|
|
154
|
+
const targetSet = getHighEndAchievementNameSet();
|
|
155
|
+
const clears = new Set();
|
|
156
|
+
let foundAny = false;
|
|
157
|
+
$("li.entry").each((_, el) => {
|
|
158
|
+
const entry = $(el);
|
|
159
|
+
const name = entry.find("p.entry__activity__txt").first().text().trim();
|
|
160
|
+
if (!targetSet.has(name))
|
|
161
|
+
return;
|
|
162
|
+
foundAny = true;
|
|
163
|
+
const hasDate = entry.find("time.entry__activity__time").length > 0;
|
|
164
|
+
if (hasDate)
|
|
165
|
+
clears.add(name);
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
status: foundAny ? "ok" : "private_or_unavailable",
|
|
169
|
+
clears: Array.from(clears)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 互換用: 旧API名(`parseUltimateClearsFromAchievementHtml`)。
|
|
174
|
+
*/
|
|
175
|
+
function parseUltimateClearsFromAchievementHtml(html) {
|
|
176
|
+
return parseHighEndClearsFromAchievementHtml(html);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Lodestone のアチーブメント一覧ページを取得します。
|
|
180
|
+
*/
|
|
181
|
+
async function fetchAchievementCategoryHtml(url) {
|
|
182
|
+
const response = await axios_1.default.get(url, {
|
|
183
|
+
responseType: "text",
|
|
184
|
+
headers: {
|
|
185
|
+
Accept: "text/html,application/xhtml+xml",
|
|
186
|
+
"Accept-Language": "ja,en;q=0.8",
|
|
187
|
+
"User-Agent": "ffxiv-lodestone-character-lookup/0.1 (+https://jp.finalfantasyxiv.com)"
|
|
188
|
+
},
|
|
189
|
+
timeout: 30_000
|
|
190
|
+
});
|
|
191
|
+
return response.data;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=lodestoneAchievements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lodestoneAchievements.js","sourceRoot":"","sources":["../src/lodestoneAchievements.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@piyoraik/ffxiv-lodestone-character-lookup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "FFXIV Lodestone character lookup (search → character URL) and high-end achievement checks",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "",
|
|
7
|
+
"homepage": "",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": ""
|
|
11
|
+
},
|
|
12
|
+
"type": "commonjs",
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"require": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/**",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-data.cjs",
|
|
30
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"axios": "^1.7.9",
|
|
35
|
+
"cheerio": "^1.1.2"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.10.2",
|
|
39
|
+
"typescript": "^5.7.2"
|
|
40
|
+
}
|
|
41
|
+
}
|