@wzyjs/utils 0.3.31 → 0.3.32
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/dist/node/crawl/fanqie/book/categories.d.ts +3 -0
- package/dist/node/crawl/fanqie/book/detail.d.ts +2 -0
- package/dist/node/crawl/fanqie/book/index.d.ts +5 -0
- package/dist/node/crawl/fanqie/book/library.d.ts +5 -0
- package/dist/node/crawl/fanqie/book/normalize.d.ts +22 -0
- package/dist/node/crawl/fanqie/book/search.d.ts +11 -0
- package/dist/node/crawl/fanqie/chapter/directory.d.ts +2 -0
- package/dist/node/crawl/fanqie/chapter/index.d.ts +1 -0
- package/dist/node/crawl/fanqie/content/index.d.ts +1 -0
- package/dist/node/crawl/fanqie/content/sidecar.d.ts +2 -0
- package/dist/node/crawl/fanqie/index.d.ts +4 -0
- package/dist/node/crawl/fanqie/types.d.ts +74 -0
- package/dist/node/crawl/fanqie/utils/book-source.d.ts +12 -0
- package/dist/node/crawl/fanqie/utils/consts.d.ts +40 -0
- package/dist/node/crawl/fanqie/utils/font-map.d.ts +2 -0
- package/dist/node/crawl/fanqie/utils/http.d.ts +1 -0
- package/dist/node/crawl/fanqie/utils/index.d.ts +2 -0
- package/dist/node/crawl/fanqie/utils/normalize.d.ts +2 -0
- package/dist/node/crawl/index.d.ts +1 -0
- package/dist/node.cjs.js +1027 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.esm.js +1027 -0
- package/package.json +2 -2
package/dist/node.esm.js
CHANGED
|
@@ -10885,7 +10885,1033 @@ var processFile = async (params) => {
|
|
|
10885
10885
|
ext
|
|
10886
10886
|
};
|
|
10887
10887
|
};
|
|
10888
|
+
// src/node/crawl/index.ts
|
|
10889
|
+
var exports_crawl = {};
|
|
10890
|
+
__export(exports_crawl, {
|
|
10891
|
+
fanqie: () => exports_fanqie
|
|
10892
|
+
});
|
|
10893
|
+
|
|
10894
|
+
// src/node/crawl/fanqie/index.ts
|
|
10895
|
+
var exports_fanqie = {};
|
|
10896
|
+
__export(exports_fanqie, {
|
|
10897
|
+
fanqieContent: () => exports_content,
|
|
10898
|
+
fanqieChapter: () => exports_chapter,
|
|
10899
|
+
fanqieBook: () => exports_book
|
|
10900
|
+
});
|
|
10901
|
+
|
|
10902
|
+
// src/node/crawl/fanqie/book/index.ts
|
|
10903
|
+
var exports_book = {};
|
|
10904
|
+
__export(exports_book, {
|
|
10905
|
+
searchFanqieBooks: () => searchFanqieBooks,
|
|
10906
|
+
resolveFanqieLibraryCategoryId: () => resolveFanqieLibraryCategoryId,
|
|
10907
|
+
normalizeFanqieSearchResults: () => normalizeFanqieSearchResults,
|
|
10908
|
+
normalizeFanqieOfficialLibraryItem: () => normalizeFanqieOfficialLibraryItem,
|
|
10909
|
+
normalizeFanqieBookTags: () => normalizeFanqieBookTags,
|
|
10910
|
+
normalizeFanqieBookStatus: () => normalizeFanqieBookStatus,
|
|
10911
|
+
normalizeFanqieBookSearchItem: () => normalizeFanqieBookSearchItem,
|
|
10912
|
+
normalizeFanqieBookDetailItem: () => normalizeFanqieBookDetailItem,
|
|
10913
|
+
listFanqieLibraryBooks: () => listFanqieLibraryBooks,
|
|
10914
|
+
getFanqieLibraryFilters: () => getFanqieLibraryFilters,
|
|
10915
|
+
getFanqieBookDetailById: () => getFanqieBookDetailById,
|
|
10916
|
+
createFanqieSearchUrl: () => createFanqieSearchUrl
|
|
10917
|
+
});
|
|
10918
|
+
|
|
10919
|
+
// src/node/crawl/fanqie/utils/consts.ts
|
|
10920
|
+
var FANQIE_LIBRARY_LIST_URL = "https://fanqienovel.com/api/author/library/book_list/v0/";
|
|
10921
|
+
var FANQIE_LIBRARY_CATEGORY_URL = "https://fanqienovel.com/api/author/book/category_list/v0/";
|
|
10922
|
+
var FANQIE_BOOK_SOURCE_SEARCH_PATH = "/search";
|
|
10923
|
+
var FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_SOURCE = "番茄";
|
|
10924
|
+
var FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_TAB = "小说";
|
|
10925
|
+
var FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_DISABLED_SOURCES = "0";
|
|
10926
|
+
var FANQIE_BOOK_SOURCE_CATALOG_PATH = "/catalog";
|
|
10927
|
+
var FANQIE_BOOK_SOURCE_CATALOG_SOURCE = "番茄";
|
|
10928
|
+
var FANQIE_BOOK_SOURCE_CATALOG_TAB = "小说";
|
|
10929
|
+
var FANQIE_BOOK_SOURCE_CATALOG_VARIABLE = { custom: "" };
|
|
10930
|
+
var FANQIE_BOOK_SOURCE_DETAIL_PATH = "/detail";
|
|
10931
|
+
var FANQIE_BOOK_SOURCE_DETAIL_SOURCE = "番茄";
|
|
10932
|
+
var FANQIE_BOOK_SOURCE_DETAIL_TAB = "小说";
|
|
10933
|
+
var FANQIE_BOOK_SOURCE_DETAIL_VARIABLE = { custom: "" };
|
|
10934
|
+
var DEFAULT_FANQIE_BOOK_SOURCE_BASE_URLS = [
|
|
10935
|
+
"https://api.langge.cf",
|
|
10936
|
+
"https://v2.czyl.cf",
|
|
10937
|
+
"http://219.154.201.122:5006"
|
|
10938
|
+
];
|
|
10939
|
+
var FANQIE_PAGE_HEADERS = {
|
|
10940
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
10941
|
+
Referer: "https://fanqienovel.com/"
|
|
10942
|
+
};
|
|
10943
|
+
var FANQIE_BOOK_SOURCE_SEARCH_HEADERS = {
|
|
10944
|
+
"user-agent": "Mozilla/5.0"
|
|
10945
|
+
};
|
|
10946
|
+
var FANQIE_BOOK_SOURCE_CATALOG_HEADERS = {
|
|
10947
|
+
"content-type": "application/json",
|
|
10948
|
+
"user-agent": "Mozilla/5.0"
|
|
10949
|
+
};
|
|
10950
|
+
var FANQIE_BOOK_SOURCE_DETAIL_HEADERS = {
|
|
10951
|
+
"content-type": "application/json",
|
|
10952
|
+
"user-agent": "Mozilla/5.0"
|
|
10953
|
+
};
|
|
10954
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_BASE_URL = "http://127.0.0.1:18423";
|
|
10955
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_CONTAINER = "tomato-novel-webui";
|
|
10956
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_JOB_TIMEOUT_MS = 5 * 60 * 1000;
|
|
10957
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_JOB_POLL_INTERVAL_MS = 1500;
|
|
10958
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_STATUS_TIMEOUT_MS = 15 * 1000;
|
|
10959
|
+
var DEFAULT_FANQIE_OFFICIAL_SIDECAR_STATUS_POLL_INTERVAL_MS = 1000;
|
|
10960
|
+
|
|
10961
|
+
// src/node/crawl/fanqie/utils/http.ts
|
|
10962
|
+
var fetchFanqieJson = async (url3, init) => {
|
|
10963
|
+
const response = await fetch(url3, {
|
|
10964
|
+
...init,
|
|
10965
|
+
cache: "no-store"
|
|
10966
|
+
});
|
|
10967
|
+
if (!response.ok) {
|
|
10968
|
+
throw new Error(`番茄请求失败: ${response.status} ${url3}`);
|
|
10969
|
+
}
|
|
10970
|
+
return await response.json();
|
|
10971
|
+
};
|
|
10972
|
+
|
|
10973
|
+
// src/node/crawl/fanqie/utils/font-map.ts
|
|
10974
|
+
var FANQIE_OBFUSCATED_FONT_MAP = {
|
|
10975
|
+
"": "D",
|
|
10976
|
+
"": "在",
|
|
10977
|
+
"": "主",
|
|
10978
|
+
"": "特",
|
|
10979
|
+
"": "家",
|
|
10980
|
+
"": "军",
|
|
10981
|
+
"": "然",
|
|
10982
|
+
"": "表",
|
|
10983
|
+
"": "场",
|
|
10984
|
+
"": "4",
|
|
10985
|
+
"": "要",
|
|
10986
|
+
"": "只",
|
|
10987
|
+
"": "v",
|
|
10988
|
+
"": "和",
|
|
10989
|
+
"": "6",
|
|
10990
|
+
"": "别",
|
|
10991
|
+
"": "还",
|
|
10992
|
+
"": "g",
|
|
10993
|
+
"": "现",
|
|
10994
|
+
"": "儿",
|
|
10995
|
+
"": "岁",
|
|
10996
|
+
"": "此",
|
|
10997
|
+
"": "象",
|
|
10998
|
+
"": "月",
|
|
10999
|
+
"": "3",
|
|
11000
|
+
"": "出",
|
|
11001
|
+
"": "战",
|
|
11002
|
+
"": "工",
|
|
11003
|
+
"": "相",
|
|
11004
|
+
"": "o",
|
|
11005
|
+
"": "男",
|
|
11006
|
+
"": "直",
|
|
11007
|
+
"": "失",
|
|
11008
|
+
"": "世",
|
|
11009
|
+
"": "F",
|
|
11010
|
+
"": "都",
|
|
11011
|
+
"": "平",
|
|
11012
|
+
"": "文",
|
|
11013
|
+
"": "什",
|
|
11014
|
+
"": "V",
|
|
11015
|
+
"": "O",
|
|
11016
|
+
"": "将",
|
|
11017
|
+
"": "真",
|
|
11018
|
+
"": "T",
|
|
11019
|
+
"": "那",
|
|
11020
|
+
"": "当",
|
|
11021
|
+
"": "会",
|
|
11022
|
+
"": "立",
|
|
11023
|
+
"": "些",
|
|
11024
|
+
"": "u",
|
|
11025
|
+
"": "是",
|
|
11026
|
+
"": "十",
|
|
11027
|
+
"": "张",
|
|
11028
|
+
"": "学",
|
|
11029
|
+
"": "气",
|
|
11030
|
+
"": "大",
|
|
11031
|
+
"": "爱",
|
|
11032
|
+
"": "两",
|
|
11033
|
+
"": "命",
|
|
11034
|
+
"": "全",
|
|
11035
|
+
"": "后",
|
|
11036
|
+
"": "东",
|
|
11037
|
+
"": "性",
|
|
11038
|
+
"": "通",
|
|
11039
|
+
"": "被",
|
|
11040
|
+
"": "1",
|
|
11041
|
+
"": "它",
|
|
11042
|
+
"": "乐",
|
|
11043
|
+
"": "接",
|
|
11044
|
+
"": "而",
|
|
11045
|
+
"": "感",
|
|
11046
|
+
"": "车",
|
|
11047
|
+
"": "山",
|
|
11048
|
+
"": "公",
|
|
11049
|
+
"": "了",
|
|
11050
|
+
"": "常",
|
|
11051
|
+
"": "以",
|
|
11052
|
+
"": "何",
|
|
11053
|
+
"": "可",
|
|
11054
|
+
"": "话",
|
|
11055
|
+
"": "先",
|
|
11056
|
+
"": "p",
|
|
11057
|
+
"": "i",
|
|
11058
|
+
"": "叫",
|
|
11059
|
+
"": "轻",
|
|
11060
|
+
"": "M",
|
|
11061
|
+
"": "士",
|
|
11062
|
+
"": "w",
|
|
11063
|
+
"": "着",
|
|
11064
|
+
"": "变",
|
|
11065
|
+
"": "尔",
|
|
11066
|
+
"": "快",
|
|
11067
|
+
"": "l",
|
|
11068
|
+
"": "个",
|
|
11069
|
+
"": "说",
|
|
11070
|
+
"": "少",
|
|
11071
|
+
"": "色",
|
|
11072
|
+
"": "里",
|
|
11073
|
+
"": "安",
|
|
11074
|
+
"": "花",
|
|
11075
|
+
"": "远",
|
|
11076
|
+
"": "7",
|
|
11077
|
+
"": "难",
|
|
11078
|
+
"": "师",
|
|
11079
|
+
"": "放",
|
|
11080
|
+
"": "t",
|
|
11081
|
+
"": "报",
|
|
11082
|
+
"": "认",
|
|
11083
|
+
"": "面",
|
|
11084
|
+
"": "道",
|
|
11085
|
+
"": "S",
|
|
11086
|
+
"": "克",
|
|
11087
|
+
"": "地",
|
|
11088
|
+
"": "度",
|
|
11089
|
+
"": "I",
|
|
11090
|
+
"": "好",
|
|
11091
|
+
"": "机",
|
|
11092
|
+
"": "U",
|
|
11093
|
+
"": "民",
|
|
11094
|
+
"": "写",
|
|
11095
|
+
"": "把",
|
|
11096
|
+
"": "万",
|
|
11097
|
+
"": "同",
|
|
11098
|
+
"": "水",
|
|
11099
|
+
"": "新",
|
|
11100
|
+
"": "没",
|
|
11101
|
+
"": "书",
|
|
11102
|
+
"": "电",
|
|
11103
|
+
"": "吃",
|
|
11104
|
+
"": "像",
|
|
11105
|
+
"": "斯",
|
|
11106
|
+
"": "5",
|
|
11107
|
+
"": "为",
|
|
11108
|
+
"": "y",
|
|
11109
|
+
"": "白",
|
|
11110
|
+
"": "几",
|
|
11111
|
+
"": "日",
|
|
11112
|
+
"": "教",
|
|
11113
|
+
"": "看",
|
|
11114
|
+
"": "但",
|
|
11115
|
+
"": "第",
|
|
11116
|
+
"": "加",
|
|
11117
|
+
"": "候",
|
|
11118
|
+
"": "作",
|
|
11119
|
+
"": "上",
|
|
11120
|
+
"": "拉",
|
|
11121
|
+
"": "住",
|
|
11122
|
+
"": "有",
|
|
11123
|
+
"": "法",
|
|
11124
|
+
"": "r",
|
|
11125
|
+
"": "事",
|
|
11126
|
+
"": "应",
|
|
11127
|
+
"": "位",
|
|
11128
|
+
"": "利",
|
|
11129
|
+
"": "你",
|
|
11130
|
+
"": "声",
|
|
11131
|
+
"": "身",
|
|
11132
|
+
"": "国",
|
|
11133
|
+
"": "问",
|
|
11134
|
+
"": "马",
|
|
11135
|
+
"": "女",
|
|
11136
|
+
"": "他",
|
|
11137
|
+
"": "Y",
|
|
11138
|
+
"": "比",
|
|
11139
|
+
"": "父",
|
|
11140
|
+
"": "x",
|
|
11141
|
+
"": "A",
|
|
11142
|
+
"": "H",
|
|
11143
|
+
"": "N",
|
|
11144
|
+
"": "s",
|
|
11145
|
+
"": "X",
|
|
11146
|
+
"": "边",
|
|
11147
|
+
"": "美",
|
|
11148
|
+
"": "对",
|
|
11149
|
+
"": "所",
|
|
11150
|
+
"": "金",
|
|
11151
|
+
"": "活",
|
|
11152
|
+
"": "回",
|
|
11153
|
+
"": "意",
|
|
11154
|
+
"": "到",
|
|
11155
|
+
"": "z",
|
|
11156
|
+
"": "从",
|
|
11157
|
+
"": "j",
|
|
11158
|
+
"": "知",
|
|
11159
|
+
"": "又",
|
|
11160
|
+
"": "内",
|
|
11161
|
+
"": "因",
|
|
11162
|
+
"": "点",
|
|
11163
|
+
"": "Q",
|
|
11164
|
+
"": "三",
|
|
11165
|
+
"": "定",
|
|
11166
|
+
"": "8",
|
|
11167
|
+
"": "R",
|
|
11168
|
+
"": "b",
|
|
11169
|
+
"": "正",
|
|
11170
|
+
"": "或",
|
|
11171
|
+
"": "夫",
|
|
11172
|
+
"": "向",
|
|
11173
|
+
"": "德",
|
|
11174
|
+
"": "听",
|
|
11175
|
+
"": "更",
|
|
11176
|
+
"": "得",
|
|
11177
|
+
"": "告",
|
|
11178
|
+
"": "并",
|
|
11179
|
+
"": "本",
|
|
11180
|
+
"": "q",
|
|
11181
|
+
"": "过",
|
|
11182
|
+
"": "记",
|
|
11183
|
+
"": "L",
|
|
11184
|
+
"": "让",
|
|
11185
|
+
"": "打",
|
|
11186
|
+
"": "f",
|
|
11187
|
+
"": "人",
|
|
11188
|
+
"": "就",
|
|
11189
|
+
"": "者",
|
|
11190
|
+
"": "去",
|
|
11191
|
+
"": "原",
|
|
11192
|
+
"": "满",
|
|
11193
|
+
"": "体",
|
|
11194
|
+
"": "做",
|
|
11195
|
+
"": "经",
|
|
11196
|
+
"": "K",
|
|
11197
|
+
"": "走",
|
|
11198
|
+
"": "如",
|
|
11199
|
+
"": "孩",
|
|
11200
|
+
"": "c",
|
|
11201
|
+
"": "G",
|
|
11202
|
+
"": "给",
|
|
11203
|
+
"": "使",
|
|
11204
|
+
"": "物",
|
|
11205
|
+
"": "最",
|
|
11206
|
+
"": "笑",
|
|
11207
|
+
"": "部",
|
|
11208
|
+
"": "员",
|
|
11209
|
+
"": "等",
|
|
11210
|
+
"": "受",
|
|
11211
|
+
"": "k",
|
|
11212
|
+
"": "行",
|
|
11213
|
+
"": "一",
|
|
11214
|
+
"": "条",
|
|
11215
|
+
"": "果",
|
|
11216
|
+
"": "动",
|
|
11217
|
+
"": "光",
|
|
11218
|
+
"": "门",
|
|
11219
|
+
"": "头",
|
|
11220
|
+
"": "见",
|
|
11221
|
+
"": "往",
|
|
11222
|
+
"": "自",
|
|
11223
|
+
"": "解",
|
|
11224
|
+
"": "成",
|
|
11225
|
+
"": "处",
|
|
11226
|
+
"": "天",
|
|
11227
|
+
"": "能",
|
|
11228
|
+
"": "于",
|
|
11229
|
+
"": "名",
|
|
11230
|
+
"": "其",
|
|
11231
|
+
"": "发",
|
|
11232
|
+
"": "总",
|
|
11233
|
+
"": "母",
|
|
11234
|
+
"": "的",
|
|
11235
|
+
"": "死",
|
|
11236
|
+
"": "手",
|
|
11237
|
+
"": "入",
|
|
11238
|
+
"": "路",
|
|
11239
|
+
"": "进",
|
|
11240
|
+
"": "心",
|
|
11241
|
+
"": "来",
|
|
11242
|
+
"": "h",
|
|
11243
|
+
"": "时",
|
|
11244
|
+
"": "力",
|
|
11245
|
+
"": "多",
|
|
11246
|
+
"": "开",
|
|
11247
|
+
"": "已",
|
|
11248
|
+
"": "许",
|
|
11249
|
+
"": "d",
|
|
11250
|
+
"": "至",
|
|
11251
|
+
"": "由",
|
|
11252
|
+
"": "很",
|
|
11253
|
+
"": "界",
|
|
11254
|
+
"": "n",
|
|
11255
|
+
"": "小",
|
|
11256
|
+
"": "与",
|
|
11257
|
+
"": "Z",
|
|
11258
|
+
"": "想",
|
|
11259
|
+
"": "代",
|
|
11260
|
+
"": "么",
|
|
11261
|
+
"": "分",
|
|
11262
|
+
"": "生",
|
|
11263
|
+
"": "口",
|
|
11264
|
+
"": "再",
|
|
11265
|
+
"": "妈",
|
|
11266
|
+
"": "望",
|
|
11267
|
+
"": "次",
|
|
11268
|
+
"": "西",
|
|
11269
|
+
"": "风",
|
|
11270
|
+
"": "种",
|
|
11271
|
+
"": "带",
|
|
11272
|
+
"": "J",
|
|
11273
|
+
"": "实",
|
|
11274
|
+
"": "情",
|
|
11275
|
+
"": "才",
|
|
11276
|
+
"": "这",
|
|
11277
|
+
"": "E",
|
|
11278
|
+
"": "我",
|
|
11279
|
+
"": "神",
|
|
11280
|
+
"": "格",
|
|
11281
|
+
"": "长",
|
|
11282
|
+
"": "觉",
|
|
11283
|
+
"": "间",
|
|
11284
|
+
"": "年",
|
|
11285
|
+
"": "眼",
|
|
11286
|
+
"": "无",
|
|
11287
|
+
"": "不",
|
|
11288
|
+
"": "亲",
|
|
11289
|
+
"": "关",
|
|
11290
|
+
"": "结",
|
|
11291
|
+
"": "0",
|
|
11292
|
+
"": "友",
|
|
11293
|
+
"": "信",
|
|
11294
|
+
"": "下",
|
|
11295
|
+
"": "却",
|
|
11296
|
+
"": "重",
|
|
11297
|
+
"": "己",
|
|
11298
|
+
"": "老",
|
|
11299
|
+
"": "2",
|
|
11300
|
+
"": "音",
|
|
11301
|
+
"": "字",
|
|
11302
|
+
"": "m",
|
|
11303
|
+
"": "呢",
|
|
11304
|
+
"": "明",
|
|
11305
|
+
"": "之",
|
|
11306
|
+
"": "前",
|
|
11307
|
+
"": "高",
|
|
11308
|
+
"": "P",
|
|
11309
|
+
"": "B",
|
|
11310
|
+
"": "目",
|
|
11311
|
+
"": "太",
|
|
11312
|
+
"": "e",
|
|
11313
|
+
"": "9",
|
|
11314
|
+
"": "起",
|
|
11315
|
+
"": "稜",
|
|
11316
|
+
"": "她",
|
|
11317
|
+
"": "也",
|
|
11318
|
+
"": "W",
|
|
11319
|
+
"": "用",
|
|
11320
|
+
"": "方",
|
|
11321
|
+
"": "子",
|
|
11322
|
+
"": "英",
|
|
11323
|
+
"": "每",
|
|
11324
|
+
"": "理",
|
|
11325
|
+
"": "便",
|
|
11326
|
+
"": "四",
|
|
11327
|
+
"": "数",
|
|
11328
|
+
"": "期",
|
|
11329
|
+
"": "中",
|
|
11330
|
+
"": "C",
|
|
11331
|
+
"": "外",
|
|
11332
|
+
"": "样",
|
|
11333
|
+
"": "a",
|
|
11334
|
+
"": "海",
|
|
11335
|
+
"": "们",
|
|
11336
|
+
"": "任"
|
|
11337
|
+
};
|
|
11338
|
+
var restoreFanqieObfuscatedText = (content) => {
|
|
11339
|
+
return Array.from(content).map((char) => FANQIE_OBFUSCATED_FONT_MAP[char] || char).join("");
|
|
11340
|
+
};
|
|
11341
|
+
|
|
11342
|
+
// src/node/crawl/fanqie/utils/normalize.ts
|
|
11343
|
+
var normalizeFanqieText = (value) => {
|
|
11344
|
+
if (value === null || value === undefined) {
|
|
11345
|
+
return null;
|
|
11346
|
+
}
|
|
11347
|
+
const normalized = restoreFanqieObfuscatedText(String(value)).trim();
|
|
11348
|
+
return normalized || null;
|
|
11349
|
+
};
|
|
11350
|
+
var normalizeFanqieCoverUrl = (value) => {
|
|
11351
|
+
const url3 = value ? String(value).trim() : "";
|
|
11352
|
+
if (!url3) {
|
|
11353
|
+
return null;
|
|
11354
|
+
}
|
|
11355
|
+
return url3.replace(/^http:\/\//, "https://");
|
|
11356
|
+
};
|
|
11357
|
+
|
|
11358
|
+
// src/node/crawl/fanqie/book/categories.ts
|
|
11359
|
+
var getCategoryGroupKey = (label) => {
|
|
11360
|
+
if (label === "主题") {
|
|
11361
|
+
return "topic";
|
|
11362
|
+
}
|
|
11363
|
+
if (label === "角色") {
|
|
11364
|
+
return "role";
|
|
11365
|
+
}
|
|
11366
|
+
if (label === "情节") {
|
|
11367
|
+
return "plot";
|
|
11368
|
+
}
|
|
11369
|
+
return null;
|
|
11370
|
+
};
|
|
11371
|
+
var createEmptyLibraryFilters = () => ({
|
|
11372
|
+
topic: [],
|
|
11373
|
+
role: [],
|
|
11374
|
+
plot: []
|
|
11375
|
+
});
|
|
11376
|
+
var normalizeFanqieLibraryFilters = (payload) => {
|
|
11377
|
+
const list = Array.isArray(payload) ? payload : [];
|
|
11378
|
+
const groups = createEmptyLibraryFilters();
|
|
11379
|
+
list.forEach((item) => {
|
|
11380
|
+
const label = String(item?.label || "").trim();
|
|
11381
|
+
const groupKey = getCategoryGroupKey(label);
|
|
11382
|
+
const categoryId = Number(item?.category_id);
|
|
11383
|
+
const name = normalizeFanqieText(item?.name);
|
|
11384
|
+
if (!groupKey || !Number.isInteger(categoryId) || !name) {
|
|
11385
|
+
return;
|
|
11386
|
+
}
|
|
11387
|
+
groups[groupKey].push({
|
|
11388
|
+
categoryId,
|
|
11389
|
+
label,
|
|
11390
|
+
name,
|
|
11391
|
+
coverUrl: normalizeFanqieCoverUrl(item?.cover_uri)
|
|
11392
|
+
});
|
|
11393
|
+
});
|
|
11394
|
+
return groups;
|
|
11395
|
+
};
|
|
11396
|
+
var getFanqieLibraryFilters = async (gender) => {
|
|
11397
|
+
const url3 = new URL(FANQIE_LIBRARY_CATEGORY_URL);
|
|
11398
|
+
url3.searchParams.set("gender", String(gender));
|
|
11399
|
+
const data = await fetchFanqieJson(url3.toString(), {
|
|
11400
|
+
headers: FANQIE_PAGE_HEADERS
|
|
11401
|
+
});
|
|
11402
|
+
return normalizeFanqieLibraryFilters(data?.data);
|
|
11403
|
+
};
|
|
11404
|
+
var resolveFanqieLibraryCategoryId = async ({
|
|
11405
|
+
gender,
|
|
11406
|
+
categoryGroup,
|
|
11407
|
+
categoryId
|
|
11408
|
+
}) => {
|
|
11409
|
+
if (categoryGroup === "all") {
|
|
11410
|
+
return -1;
|
|
11411
|
+
}
|
|
11412
|
+
const groups = await getFanqieLibraryFilters(gender);
|
|
11413
|
+
const currentGroup = groups[categoryGroup];
|
|
11414
|
+
if (currentGroup.length === 0) {
|
|
11415
|
+
return -1;
|
|
11416
|
+
}
|
|
11417
|
+
const matchedItem = typeof categoryId === "number" ? currentGroup.find((item) => item.categoryId === categoryId) : null;
|
|
11418
|
+
return matchedItem?.categoryId || currentGroup[0]?.categoryId || -1;
|
|
11419
|
+
};
|
|
11420
|
+
// src/node/crawl/fanqie/utils/book-source.ts
|
|
11421
|
+
var getFanqieBookSourceBaseUrls = () => {
|
|
11422
|
+
const raw = process.env.FANQIE_BOOK_SOURCE_BASE_URLS?.trim() || process.env.FANQIE_BOOK_SOURCE_DETAIL_BASE_URLS?.trim();
|
|
11423
|
+
if (!raw) {
|
|
11424
|
+
return [...DEFAULT_FANQIE_BOOK_SOURCE_BASE_URLS];
|
|
11425
|
+
}
|
|
11426
|
+
const list = raw.split(",").map((item) => item.trim()).filter(Boolean);
|
|
11427
|
+
return list.length > 0 ? list : [...DEFAULT_FANQIE_BOOK_SOURCE_BASE_URLS];
|
|
11428
|
+
};
|
|
11429
|
+
var encodeFanqieBookSourceBookId = (fanqieBookId) => {
|
|
11430
|
+
return Buffer.from(fanqieBookId, "utf8").toString("base64");
|
|
11431
|
+
};
|
|
11432
|
+
var decodeFanqieBookSourceBookId = (encodedBookId) => {
|
|
11433
|
+
const raw = encodedBookId ? String(encodedBookId).trim() : "";
|
|
11434
|
+
if (!raw) {
|
|
11435
|
+
return "";
|
|
11436
|
+
}
|
|
11437
|
+
try {
|
|
11438
|
+
const normalized = raw.replace(/-/g, "+").replace(/_/g, "/").padEnd(raw.length + (4 - raw.length % 4) % 4, "=");
|
|
11439
|
+
const decoded = Buffer.from(normalized, "base64").toString("utf8").trim();
|
|
11440
|
+
return /^\d+$/.test(decoded) ? decoded : raw;
|
|
11441
|
+
} catch {
|
|
11442
|
+
return raw;
|
|
11443
|
+
}
|
|
11444
|
+
};
|
|
11445
|
+
var createFanqieBookSourceUrl = (baseUrl, path3, searchParams) => {
|
|
11446
|
+
const url3 = new URL(path3, baseUrl);
|
|
11447
|
+
Object.entries(searchParams).forEach(([key2, value]) => {
|
|
11448
|
+
url3.searchParams.set(key2, value);
|
|
11449
|
+
});
|
|
11450
|
+
return url3.toString();
|
|
11451
|
+
};
|
|
11452
|
+
var requestFanqieBookSourceJson = async ({
|
|
11453
|
+
path: path3,
|
|
11454
|
+
searchParams,
|
|
11455
|
+
init,
|
|
11456
|
+
baseUrl,
|
|
11457
|
+
errorPrefix,
|
|
11458
|
+
validate
|
|
11459
|
+
}) => {
|
|
11460
|
+
const baseUrls = baseUrl ? [baseUrl] : getFanqieBookSourceBaseUrls();
|
|
11461
|
+
const errors2 = [];
|
|
11462
|
+
for (const currentBaseUrl of baseUrls) {
|
|
11463
|
+
try {
|
|
11464
|
+
const url3 = createFanqieBookSourceUrl(currentBaseUrl, path3, searchParams);
|
|
11465
|
+
const response = await fetchFanqieJson(url3, init);
|
|
11466
|
+
validate?.(response);
|
|
11467
|
+
return response;
|
|
11468
|
+
} catch (error) {
|
|
11469
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11470
|
+
errors2.push(`${currentBaseUrl}: ${message}`);
|
|
11471
|
+
}
|
|
11472
|
+
}
|
|
11473
|
+
throw new Error(`${errorPrefix}: ${errors2.join(" | ")}`);
|
|
11474
|
+
};
|
|
10888
11475
|
|
|
11476
|
+
// src/node/crawl/fanqie/book/normalize.ts
|
|
11477
|
+
var normalizeFanqieSearchTitle = (value) => {
|
|
11478
|
+
const normalized = normalizeFanqieText(value);
|
|
11479
|
+
if (!normalized) {
|
|
11480
|
+
return "";
|
|
11481
|
+
}
|
|
11482
|
+
return normalized.replace(/(别名:.*?)/g, "").trim();
|
|
11483
|
+
};
|
|
11484
|
+
var normalizeFanqieBookStatus = (value) => {
|
|
11485
|
+
const normalized = normalizeFanqieText(value);
|
|
11486
|
+
if (!normalized) {
|
|
11487
|
+
return null;
|
|
11488
|
+
}
|
|
11489
|
+
if (normalized.includes("完结")) {
|
|
11490
|
+
return 1;
|
|
11491
|
+
}
|
|
11492
|
+
if (normalized.includes("连载")) {
|
|
11493
|
+
return 0;
|
|
11494
|
+
}
|
|
11495
|
+
return null;
|
|
11496
|
+
};
|
|
11497
|
+
var normalizeFanqieBookTags = (value) => {
|
|
11498
|
+
const normalized = normalizeFanqieText(value);
|
|
11499
|
+
if (!normalized) {
|
|
11500
|
+
return [];
|
|
11501
|
+
}
|
|
11502
|
+
return normalized.split(/[,,、\s]+/).map((item) => item.trim()).filter(Boolean);
|
|
11503
|
+
};
|
|
11504
|
+
var createFanqieBookItemBase = (payload) => ({
|
|
11505
|
+
author: normalizeFanqieText(payload.author),
|
|
11506
|
+
score: normalizeFanqieText(payload.score),
|
|
11507
|
+
coverUrl: normalizeFanqieCoverUrl(payload.thumb_url),
|
|
11508
|
+
description: normalizeFanqieText(payload.abstract),
|
|
11509
|
+
category: normalizeFanqieText(payload.category),
|
|
11510
|
+
tags: normalizeFanqieBookTags(payload.tags),
|
|
11511
|
+
wordCount: normalizeFanqieText(payload.word_number),
|
|
11512
|
+
readCount: normalizeFanqieText(payload.read_count),
|
|
11513
|
+
readCountAll: normalizeFanqieText(payload.read_count_all),
|
|
11514
|
+
creationStatus: normalizeFanqieBookStatus(payload.status),
|
|
11515
|
+
lastChapterTime: normalizeFanqieText(payload.last_chapter_update_time),
|
|
11516
|
+
rawTitle: payload.book_name ? String(payload.book_name) : null,
|
|
11517
|
+
rawAuthor: payload.author ? String(payload.author) : null,
|
|
11518
|
+
rawDescription: payload.abstract ? String(payload.abstract) : null,
|
|
11519
|
+
rawCategory: payload.category ? String(payload.category) : null,
|
|
11520
|
+
rawScore: payload.score ? String(payload.score) : null,
|
|
11521
|
+
rawWordCount: payload.word_number ? String(payload.word_number) : null,
|
|
11522
|
+
rawReadCount: payload.read_count ? String(payload.read_count) : null,
|
|
11523
|
+
rawReadCountAll: payload.read_count_all ? String(payload.read_count_all) : null
|
|
11524
|
+
});
|
|
11525
|
+
var normalizeFanqieBookSearchItem = (payload) => {
|
|
11526
|
+
const id = decodeFanqieBookSourceBookId(payload.book_id);
|
|
11527
|
+
const title = normalizeFanqieSearchTitle(payload.book_name);
|
|
11528
|
+
if (!id || !title) {
|
|
11529
|
+
return null;
|
|
11530
|
+
}
|
|
11531
|
+
return {
|
|
11532
|
+
id,
|
|
11533
|
+
title,
|
|
11534
|
+
...createFanqieBookItemBase(payload)
|
|
11535
|
+
};
|
|
11536
|
+
};
|
|
11537
|
+
var normalizeFanqieBookDetailItem = (fanqieBookId, payload) => {
|
|
11538
|
+
const title = normalizeFanqieText(payload.book_name);
|
|
11539
|
+
if (!title) {
|
|
11540
|
+
throw new Error("书源详情缺少书名");
|
|
11541
|
+
}
|
|
11542
|
+
return {
|
|
11543
|
+
id: fanqieBookId,
|
|
11544
|
+
title,
|
|
11545
|
+
...createFanqieBookItemBase(payload)
|
|
11546
|
+
};
|
|
11547
|
+
};
|
|
11548
|
+
var normalizeFanqieOfficialLibraryItem = (payload) => {
|
|
11549
|
+
const id = payload?.book_id ? String(payload.book_id).trim() : "";
|
|
11550
|
+
const title = normalizeFanqieText(payload?.book_name);
|
|
11551
|
+
if (!id || !title) {
|
|
11552
|
+
return null;
|
|
11553
|
+
}
|
|
11554
|
+
return {
|
|
11555
|
+
id,
|
|
11556
|
+
title,
|
|
11557
|
+
author: normalizeFanqieText(payload?.author),
|
|
11558
|
+
coverUrl: normalizeFanqieCoverUrl(payload?.thumb_url),
|
|
11559
|
+
description: normalizeFanqieText(payload?.abstract),
|
|
11560
|
+
category: normalizeFanqieText(payload?.category),
|
|
11561
|
+
tags: [],
|
|
11562
|
+
wordCount: normalizeFanqieText(payload?.word_count),
|
|
11563
|
+
readCount: normalizeFanqieText(payload?.read_count),
|
|
11564
|
+
readCountAll: null,
|
|
11565
|
+
creationStatus: payload?.creation_status === 0 || payload?.creation_status === 1 ? payload.creation_status : null,
|
|
11566
|
+
lastChapterTime: payload?.last_chapter_time ? String(payload.last_chapter_time) : null,
|
|
11567
|
+
rawTitle: payload?.book_name ? String(payload.book_name) : null,
|
|
11568
|
+
rawAuthor: payload?.author ? String(payload.author) : null,
|
|
11569
|
+
rawDescription: payload?.abstract ? String(payload.abstract) : null,
|
|
11570
|
+
rawCategory: payload?.category ? String(payload.category) : null,
|
|
11571
|
+
rawScore: null,
|
|
11572
|
+
rawWordCount: payload?.word_count ? String(payload.word_count) : null,
|
|
11573
|
+
rawReadCount: payload?.read_count ? String(payload.read_count) : null,
|
|
11574
|
+
rawReadCountAll: null
|
|
11575
|
+
};
|
|
11576
|
+
};
|
|
11577
|
+
|
|
11578
|
+
// src/node/crawl/fanqie/book/detail.ts
|
|
11579
|
+
var getFanqieBookDetailById = async (fanqieBookId) => {
|
|
11580
|
+
const response = await requestFanqieBookSourceJson({
|
|
11581
|
+
path: FANQIE_BOOK_SOURCE_DETAIL_PATH,
|
|
11582
|
+
searchParams: {
|
|
11583
|
+
book_id: encodeFanqieBookSourceBookId(fanqieBookId),
|
|
11584
|
+
source: FANQIE_BOOK_SOURCE_DETAIL_SOURCE,
|
|
11585
|
+
tab: FANQIE_BOOK_SOURCE_DETAIL_TAB,
|
|
11586
|
+
variable: JSON.stringify(FANQIE_BOOK_SOURCE_DETAIL_VARIABLE)
|
|
11587
|
+
},
|
|
11588
|
+
init: {
|
|
11589
|
+
method: "POST",
|
|
11590
|
+
headers: FANQIE_BOOK_SOURCE_DETAIL_HEADERS,
|
|
11591
|
+
body: JSON.stringify({ html: "" })
|
|
11592
|
+
},
|
|
11593
|
+
errorPrefix: "番茄书籍详情获取失败",
|
|
11594
|
+
validate: (data) => {
|
|
11595
|
+
if (data?.code !== 0 || !data.data) {
|
|
11596
|
+
throw new Error(data?.msg || "书源详情返回为空");
|
|
11597
|
+
}
|
|
11598
|
+
}
|
|
11599
|
+
});
|
|
11600
|
+
return normalizeFanqieBookDetailItem(fanqieBookId, response.data);
|
|
11601
|
+
};
|
|
11602
|
+
// src/node/crawl/fanqie/book/library.ts
|
|
11603
|
+
var normalizeFanqieLibraryResults = (payload) => {
|
|
11604
|
+
const list = Array.isArray(payload) ? payload : [];
|
|
11605
|
+
return list.flatMap((item) => {
|
|
11606
|
+
const result = normalizeFanqieOfficialLibraryItem(item);
|
|
11607
|
+
return result ? [result] : [];
|
|
11608
|
+
});
|
|
11609
|
+
};
|
|
11610
|
+
var listFanqieLibraryBooks = async ({
|
|
11611
|
+
gender,
|
|
11612
|
+
categoryId,
|
|
11613
|
+
creationStatus,
|
|
11614
|
+
wordCount,
|
|
11615
|
+
sort,
|
|
11616
|
+
pageIndex,
|
|
11617
|
+
pageSize
|
|
11618
|
+
}) => {
|
|
11619
|
+
const url3 = new URL(FANQIE_LIBRARY_LIST_URL);
|
|
11620
|
+
url3.searchParams.set("page_count", String(pageSize));
|
|
11621
|
+
url3.searchParams.set("page_index", String(pageIndex));
|
|
11622
|
+
url3.searchParams.set("gender", String(gender));
|
|
11623
|
+
url3.searchParams.set("category_id", String(categoryId));
|
|
11624
|
+
url3.searchParams.set("creation_status", String(creationStatus));
|
|
11625
|
+
url3.searchParams.set("word_count", String(wordCount));
|
|
11626
|
+
url3.searchParams.set("book_type", "-1");
|
|
11627
|
+
url3.searchParams.set("sort", String(sort));
|
|
11628
|
+
const data = await fetchFanqieJson(url3.toString(), {
|
|
11629
|
+
headers: FANQIE_PAGE_HEADERS
|
|
11630
|
+
});
|
|
11631
|
+
return {
|
|
11632
|
+
results: normalizeFanqieLibraryResults(data?.data?.book_list),
|
|
11633
|
+
total: Number(data?.data?.total_count || 0)
|
|
11634
|
+
};
|
|
11635
|
+
};
|
|
11636
|
+
// src/node/crawl/fanqie/book/search.ts
|
|
11637
|
+
var createFanqieBookSourceSearchUrl = (baseUrl, query, options = {}) => {
|
|
11638
|
+
return createFanqieBookSourceUrl(baseUrl, FANQIE_BOOK_SOURCE_SEARCH_PATH, {
|
|
11639
|
+
title: query,
|
|
11640
|
+
tab: options.tab || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_TAB,
|
|
11641
|
+
source: options.source || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_SOURCE,
|
|
11642
|
+
page: String(options.page || 1),
|
|
11643
|
+
disabled_sources: options.disabledSources || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_DISABLED_SOURCES
|
|
11644
|
+
});
|
|
11645
|
+
};
|
|
11646
|
+
var normalizeFanqieSearchResults = (payload) => {
|
|
11647
|
+
const list = Array.isArray(payload) ? payload : [];
|
|
11648
|
+
return list.flatMap((item) => {
|
|
11649
|
+
const result = normalizeFanqieBookSearchItem(item);
|
|
11650
|
+
return result ? [result] : [];
|
|
11651
|
+
});
|
|
11652
|
+
};
|
|
11653
|
+
var createFanqieSearchUrl = (query, options = {}) => {
|
|
11654
|
+
const baseUrl = options.baseUrl || getFanqieBookSourceBaseUrls()[0];
|
|
11655
|
+
return createFanqieBookSourceSearchUrl(baseUrl, query, options);
|
|
11656
|
+
};
|
|
11657
|
+
var searchFanqieBooks = async (query, options = {}) => {
|
|
11658
|
+
const response = await requestFanqieBookSourceJson({
|
|
11659
|
+
path: FANQIE_BOOK_SOURCE_SEARCH_PATH,
|
|
11660
|
+
baseUrl: options.baseUrl,
|
|
11661
|
+
searchParams: {
|
|
11662
|
+
title: query,
|
|
11663
|
+
tab: options.tab || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_TAB,
|
|
11664
|
+
source: options.source || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_SOURCE,
|
|
11665
|
+
page: String(options.page || 1),
|
|
11666
|
+
disabled_sources: options.disabledSources || FANQIE_BOOK_SOURCE_SEARCH_DEFAULT_DISABLED_SOURCES
|
|
11667
|
+
},
|
|
11668
|
+
init: {
|
|
11669
|
+
method: "GET",
|
|
11670
|
+
headers: FANQIE_BOOK_SOURCE_SEARCH_HEADERS
|
|
11671
|
+
},
|
|
11672
|
+
errorPrefix: "番茄书籍搜索失败",
|
|
11673
|
+
validate: (data) => {
|
|
11674
|
+
if (data?.code !== 0) {
|
|
11675
|
+
throw new Error(data?.msg || "书源搜索失败");
|
|
11676
|
+
}
|
|
11677
|
+
}
|
|
11678
|
+
});
|
|
11679
|
+
return normalizeFanqieSearchResults(response.data);
|
|
11680
|
+
};
|
|
11681
|
+
// src/node/crawl/fanqie/chapter/index.ts
|
|
11682
|
+
var exports_chapter = {};
|
|
11683
|
+
__export(exports_chapter, {
|
|
11684
|
+
getFanqieChapterDirectory: () => getFanqieChapterDirectory
|
|
11685
|
+
});
|
|
11686
|
+
|
|
11687
|
+
// src/node/crawl/fanqie/chapter/directory.ts
|
|
11688
|
+
var extractVolumeName = (value) => {
|
|
11689
|
+
const normalized = normalizeFanqieText(value);
|
|
11690
|
+
if (!normalized) {
|
|
11691
|
+
return null;
|
|
11692
|
+
}
|
|
11693
|
+
const [volumeName] = normalized.split("|").map((item) => item.trim());
|
|
11694
|
+
return volumeName || null;
|
|
11695
|
+
};
|
|
11696
|
+
var normalizeFanqieBookSourceCatalog = (payload) => {
|
|
11697
|
+
const list = Array.isArray(payload) ? payload : [];
|
|
11698
|
+
return list.map((item, index) => ({
|
|
11699
|
+
fanqieChapterId: item?.item_id ? String(item.item_id).trim() : "",
|
|
11700
|
+
title: normalizeFanqieText(item?.title) || `第${index + 1}章`,
|
|
11701
|
+
chapterOrder: index + 1,
|
|
11702
|
+
volumeName: extractVolumeName(item?.first_pass_time)
|
|
11703
|
+
})).filter((item) => Boolean(item.fanqieChapterId));
|
|
11704
|
+
};
|
|
11705
|
+
var getFanqieChapterDirectory = async (fanqieBookId) => {
|
|
11706
|
+
const response = await requestFanqieBookSourceJson({
|
|
11707
|
+
path: FANQIE_BOOK_SOURCE_CATALOG_PATH,
|
|
11708
|
+
searchParams: {
|
|
11709
|
+
book_id: encodeFanqieBookSourceBookId(fanqieBookId),
|
|
11710
|
+
source: FANQIE_BOOK_SOURCE_CATALOG_SOURCE,
|
|
11711
|
+
tab: FANQIE_BOOK_SOURCE_CATALOG_TAB,
|
|
11712
|
+
variable: JSON.stringify(FANQIE_BOOK_SOURCE_CATALOG_VARIABLE)
|
|
11713
|
+
},
|
|
11714
|
+
init: {
|
|
11715
|
+
method: "POST",
|
|
11716
|
+
headers: FANQIE_BOOK_SOURCE_CATALOG_HEADERS,
|
|
11717
|
+
body: JSON.stringify({ html: "" })
|
|
11718
|
+
},
|
|
11719
|
+
errorPrefix: "番茄章节目录获取失败",
|
|
11720
|
+
validate: (data) => {
|
|
11721
|
+
if (data?.code !== 0) {
|
|
11722
|
+
throw new Error(data?.msg || "章节目录接口返回异常");
|
|
11723
|
+
}
|
|
11724
|
+
}
|
|
11725
|
+
});
|
|
11726
|
+
return normalizeFanqieBookSourceCatalog(response.data);
|
|
11727
|
+
};
|
|
11728
|
+
// src/node/crawl/fanqie/content/index.ts
|
|
11729
|
+
var exports_content = {};
|
|
11730
|
+
__export(exports_content, {
|
|
11731
|
+
getFanqieChapterContents: () => getFanqieChapterContents
|
|
11732
|
+
});
|
|
11733
|
+
|
|
11734
|
+
// src/node/crawl/fanqie/content/sidecar.ts
|
|
11735
|
+
import { execFile } from "node:child_process";
|
|
11736
|
+
import { promisify } from "node:util";
|
|
11737
|
+
var execFileAsync = promisify(execFile);
|
|
11738
|
+
var sleep = async (ms) => {
|
|
11739
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
11740
|
+
};
|
|
11741
|
+
var assertFanqieNumericId = (value, label) => {
|
|
11742
|
+
if (!/^\d+$/.test(value.trim())) {
|
|
11743
|
+
throw new Error(`${label} 格式不正确`);
|
|
11744
|
+
}
|
|
11745
|
+
};
|
|
11746
|
+
var resolveSidecarOptions = (options = {}) => ({
|
|
11747
|
+
baseUrl: options.baseUrl || process.env.FANQIE_OFFICIAL_SIDECAR_BASE_URL || DEFAULT_FANQIE_OFFICIAL_SIDECAR_BASE_URL,
|
|
11748
|
+
container: options.container || process.env.FANQIE_OFFICIAL_SIDECAR_CONTAINER || DEFAULT_FANQIE_OFFICIAL_SIDECAR_CONTAINER,
|
|
11749
|
+
password: options.password ?? process.env.FANQIE_OFFICIAL_SIDECAR_PASSWORD ?? "",
|
|
11750
|
+
jobTimeoutMs: options.jobTimeoutMs || DEFAULT_FANQIE_OFFICIAL_SIDECAR_JOB_TIMEOUT_MS,
|
|
11751
|
+
jobPollIntervalMs: options.jobPollIntervalMs || DEFAULT_FANQIE_OFFICIAL_SIDECAR_JOB_POLL_INTERVAL_MS,
|
|
11752
|
+
statusTimeoutMs: options.statusTimeoutMs || DEFAULT_FANQIE_OFFICIAL_SIDECAR_STATUS_TIMEOUT_MS,
|
|
11753
|
+
statusPollIntervalMs: options.statusPollIntervalMs || DEFAULT_FANQIE_OFFICIAL_SIDECAR_STATUS_POLL_INTERVAL_MS
|
|
11754
|
+
});
|
|
11755
|
+
var getOfficialSidecarHeaders = (password) => {
|
|
11756
|
+
if (!password) {
|
|
11757
|
+
return {};
|
|
11758
|
+
}
|
|
11759
|
+
return {
|
|
11760
|
+
"x-tomato-password": password
|
|
11761
|
+
};
|
|
11762
|
+
};
|
|
11763
|
+
var officialSidecarFetchJson = async (path3, options, init) => {
|
|
11764
|
+
const response = await fetch(`${options.baseUrl}${path3}`, {
|
|
11765
|
+
...init,
|
|
11766
|
+
headers: {
|
|
11767
|
+
...getOfficialSidecarHeaders(options.password),
|
|
11768
|
+
...init?.headers || {}
|
|
11769
|
+
},
|
|
11770
|
+
cache: "no-store"
|
|
11771
|
+
});
|
|
11772
|
+
if (!response.ok) {
|
|
11773
|
+
throw new Error(`官方正文服务请求失败: ${response.status} ${path3}`);
|
|
11774
|
+
}
|
|
11775
|
+
return await response.json();
|
|
11776
|
+
};
|
|
11777
|
+
var submitOfficialSidecarChoice = async (jobId, type, value, options) => {
|
|
11778
|
+
await officialSidecarFetchJson(`/api/jobs/${jobId}/${type}`, options, {
|
|
11779
|
+
method: "POST",
|
|
11780
|
+
headers: {
|
|
11781
|
+
"content-type": "application/json"
|
|
11782
|
+
},
|
|
11783
|
+
body: JSON.stringify({ value })
|
|
11784
|
+
});
|
|
11785
|
+
};
|
|
11786
|
+
var createOfficialSidecarJob = async (fanqieBookId, rangeEnd, options) => {
|
|
11787
|
+
return await officialSidecarFetchJson("/api/jobs", options, {
|
|
11788
|
+
method: "POST",
|
|
11789
|
+
headers: {
|
|
11790
|
+
"content-type": "application/json"
|
|
11791
|
+
},
|
|
11792
|
+
body: JSON.stringify({
|
|
11793
|
+
book_id: fanqieBookId,
|
|
11794
|
+
range_start: 1,
|
|
11795
|
+
range_end: rangeEnd
|
|
11796
|
+
})
|
|
11797
|
+
});
|
|
11798
|
+
};
|
|
11799
|
+
var pollOfficialSidecarJobUntilDone = async (jobId, options) => {
|
|
11800
|
+
const startedAt = Date.now();
|
|
11801
|
+
while (Date.now() - startedAt < options.jobTimeoutMs) {
|
|
11802
|
+
const response = await officialSidecarFetchJson(`/api/jobs?id=${jobId}`, options);
|
|
11803
|
+
const job = response.items[0];
|
|
11804
|
+
if (!job) {
|
|
11805
|
+
throw new Error("官方正文服务任务不存在");
|
|
11806
|
+
}
|
|
11807
|
+
if (job.book_name_options?.length) {
|
|
11808
|
+
await submitOfficialSidecarChoice(jobId, "book_name", job.book_name_options[0]?.value || "", options);
|
|
11809
|
+
await sleep(300);
|
|
11810
|
+
continue;
|
|
11811
|
+
}
|
|
11812
|
+
if (job.format_options?.length) {
|
|
11813
|
+
await submitOfficialSidecarChoice(jobId, "format", job.format_options[0]?.value || "", options);
|
|
11814
|
+
await sleep(300);
|
|
11815
|
+
continue;
|
|
11816
|
+
}
|
|
11817
|
+
if (job.state === "done") {
|
|
11818
|
+
return;
|
|
11819
|
+
}
|
|
11820
|
+
if (job.state === "failed") {
|
|
11821
|
+
throw new Error(job.message || "官方正文服务任务失败");
|
|
11822
|
+
}
|
|
11823
|
+
if (job.state === "canceled") {
|
|
11824
|
+
throw new Error("官方正文服务任务已取消");
|
|
11825
|
+
}
|
|
11826
|
+
await sleep(options.jobPollIntervalMs);
|
|
11827
|
+
}
|
|
11828
|
+
throw new Error("官方正文服务任务超时");
|
|
11829
|
+
};
|
|
11830
|
+
var deleteOfficialSidecarJob = async (jobId, options) => {
|
|
11831
|
+
try {
|
|
11832
|
+
await fetch(`${options.baseUrl}/api/jobs/${jobId}`, {
|
|
11833
|
+
method: "DELETE",
|
|
11834
|
+
headers: getOfficialSidecarHeaders(options.password),
|
|
11835
|
+
cache: "no-store"
|
|
11836
|
+
});
|
|
11837
|
+
} catch {}
|
|
11838
|
+
};
|
|
11839
|
+
var tryReadOfficialSidecarStatusJson = async (fanqieBookId, options) => {
|
|
11840
|
+
assertFanqieNumericId(fanqieBookId, "书籍 ID");
|
|
11841
|
+
const shell = [
|
|
11842
|
+
'folder=""',
|
|
11843
|
+
`for candidate in /app/${fanqieBookId}_*; do [ -f "$candidate/status.json" ] && folder="$candidate" && break; done`,
|
|
11844
|
+
'[ -n "$folder" ] || exit 11',
|
|
11845
|
+
'cat "$folder/status.json"'
|
|
11846
|
+
].join("; ");
|
|
11847
|
+
try {
|
|
11848
|
+
const { stdout } = await execFileAsync("docker", ["exec", options.container, "sh", "-lc", shell], {
|
|
11849
|
+
maxBuffer: 200 * 1024 * 1024
|
|
11850
|
+
});
|
|
11851
|
+
return JSON.parse(stdout);
|
|
11852
|
+
} catch (error) {
|
|
11853
|
+
const execError = error;
|
|
11854
|
+
if (execError.code === 11) {
|
|
11855
|
+
return null;
|
|
11856
|
+
}
|
|
11857
|
+
throw new Error(execError.stderr?.trim() || execError.message || "读取官方正文服务状态失败");
|
|
11858
|
+
}
|
|
11859
|
+
};
|
|
11860
|
+
var readOfficialSidecarStatusJson = async (fanqieBookId, options) => {
|
|
11861
|
+
const startedAt = Date.now();
|
|
11862
|
+
let lastError = null;
|
|
11863
|
+
while (Date.now() - startedAt < options.statusTimeoutMs) {
|
|
11864
|
+
try {
|
|
11865
|
+
const status = await tryReadOfficialSidecarStatusJson(fanqieBookId, options);
|
|
11866
|
+
if (status) {
|
|
11867
|
+
return status;
|
|
11868
|
+
}
|
|
11869
|
+
} catch (error) {
|
|
11870
|
+
lastError = error instanceof Error ? error : new Error(error?.message || "读取官方正文服务状态失败");
|
|
11871
|
+
}
|
|
11872
|
+
await sleep(options.statusPollIntervalMs);
|
|
11873
|
+
}
|
|
11874
|
+
if (lastError) {
|
|
11875
|
+
throw lastError;
|
|
11876
|
+
}
|
|
11877
|
+
throw new Error("官方正文服务任务已完成,但未找到 status.json 结果文件");
|
|
11878
|
+
};
|
|
11879
|
+
var getFanqieChapterContents = async (fanqieBookId, chapterIds, sidecarOptions) => {
|
|
11880
|
+
assertFanqieNumericId(fanqieBookId, "书籍 ID");
|
|
11881
|
+
const normalizedChapterIds = chapterIds.map((item) => item.trim()).filter(Boolean);
|
|
11882
|
+
if (normalizedChapterIds.length === 0) {
|
|
11883
|
+
return new Map;
|
|
11884
|
+
}
|
|
11885
|
+
const options = resolveSidecarOptions(sidecarOptions);
|
|
11886
|
+
let jobId = null;
|
|
11887
|
+
try {
|
|
11888
|
+
const job = await createOfficialSidecarJob(fanqieBookId, normalizedChapterIds.length, options);
|
|
11889
|
+
jobId = job.id;
|
|
11890
|
+
await pollOfficialSidecarJobUntilDone(job.id, options);
|
|
11891
|
+
const status = await readOfficialSidecarStatusJson(fanqieBookId, options);
|
|
11892
|
+
const downloaded = status.downloaded || {};
|
|
11893
|
+
const result = new Map;
|
|
11894
|
+
normalizedChapterIds.forEach((chapterId, index) => {
|
|
11895
|
+
const item = downloaded[chapterId];
|
|
11896
|
+
if (!item?.[1]) {
|
|
11897
|
+
return;
|
|
11898
|
+
}
|
|
11899
|
+
result.set(chapterId, {
|
|
11900
|
+
title: item[0] || `第${index + 1}章`,
|
|
11901
|
+
content: item[1],
|
|
11902
|
+
chapterOrder: index + 1
|
|
11903
|
+
});
|
|
11904
|
+
});
|
|
11905
|
+
if (result.size === 0) {
|
|
11906
|
+
throw new Error("官方正文服务未返回可用章节内容");
|
|
11907
|
+
}
|
|
11908
|
+
return result;
|
|
11909
|
+
} finally {
|
|
11910
|
+
if (jobId) {
|
|
11911
|
+
await deleteOfficialSidecarJob(jobId, options);
|
|
11912
|
+
}
|
|
11913
|
+
}
|
|
11914
|
+
};
|
|
10889
11915
|
// src/node.ts
|
|
10890
11916
|
var _ = import_lodash.default;
|
|
10891
11917
|
export {
|
|
@@ -10972,6 +11998,7 @@ export {
|
|
|
10972
11998
|
dateType as date,
|
|
10973
11999
|
custom,
|
|
10974
12000
|
exports_cron as cron,
|
|
12001
|
+
exports_crawl as crawl,
|
|
10975
12002
|
default4 as consola,
|
|
10976
12003
|
coerce,
|
|
10977
12004
|
cheerio,
|