@openzim/libzim 2.4.4 → 3.1.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.
@@ -0,0 +1,462 @@
1
+ #pragma once
2
+
3
+ #include <napi.h>
4
+ #include <zim/writer/contentProvider.h>
5
+ #include <zim/writer/item.h>
6
+
7
+ #include <exception>
8
+ #include <functional>
9
+ #include <future>
10
+ #include <memory>
11
+ #include <optional>
12
+ #include <string>
13
+ #include <string_view>
14
+ #include <thread>
15
+
16
+ #include "blob.h"
17
+ #include "common.h"
18
+ #include "contentProvider.h"
19
+
20
+ zim::writer::Hints Object2Hints(const Napi::Object &obj) {
21
+ zim::writer::Hints hints{};
22
+ if (obj.Has("COMPRESS")) {
23
+ hints[zim::writer::COMPRESS] = obj["COMPRESS"].ToNumber().Int64Value();
24
+ }
25
+
26
+ if (obj.Has("FRONT_ARTICLE")) {
27
+ hints[zim::writer::FRONT_ARTICLE] =
28
+ obj["FRONT_ARTICLE"].ToNumber().Int64Value();
29
+ }
30
+
31
+ return hints;
32
+ }
33
+
34
+ /**
35
+ * Wraps a JS World Object to IndexData and implements IndexData
36
+ */
37
+ class IndexDataWrapper : public zim::writer::IndexData {
38
+ public:
39
+ explicit IndexDataWrapper(const Napi::Object &indexData)
40
+ : hasIndexData_{true},
41
+ title_{},
42
+ content_{},
43
+ keywords_{},
44
+ wordcount_{},
45
+ position_{std::nullopt} {
46
+ if (indexData.Has("hasIndexData"))
47
+ hasIndexData_ = indexData.Get("hasIndexData").ToBoolean();
48
+
49
+ if (!hasIndexData_) return;
50
+
51
+ if (indexData.Has("title")) title_ = indexData.Get("title").ToString();
52
+ if (indexData.Has("content"))
53
+ content_ = indexData.Get("content").ToString();
54
+ if (indexData.Has("keywords"))
55
+ keywords_ = indexData.Get("keywords").ToString();
56
+ if (indexData.Has("wordcount"))
57
+ wordcount_ = indexData.Get("wordcount").ToNumber();
58
+
59
+ if (indexData.Has("position") && indexData.Get("position").IsArray()) {
60
+ auto pos = indexData.Get("position").As<Napi::Array>();
61
+ if (pos.Length() < 3) {
62
+ throw Napi::Error::New(indexData.Env(),
63
+ "position must have a length of 3");
64
+ }
65
+ position_ =
66
+ std::make_tuple(pos.Get((uint32_t)0).ToBoolean().Value(),
67
+ pos.Get((uint32_t)1).ToNumber().DoubleValue(),
68
+ pos.Get((uint32_t)2).ToNumber().DoubleValue());
69
+ }
70
+
71
+ hasIndexData_ = !(title_.empty() && content_.empty() && keywords_.empty() &&
72
+ wordcount_ > 0 && !position_.has_value());
73
+ }
74
+
75
+ bool hasIndexData() const override { return hasIndexData_; }
76
+
77
+ std::string getTitle() const override { return title_; }
78
+ std::string getContent() const override { return content_; }
79
+ std::string getKeywords() const override { return keywords_; }
80
+ uint32_t getWordCount() const override { return wordcount_; }
81
+ GeoPosition getGeoPosition() const override { return *position_; }
82
+
83
+ private:
84
+ bool hasIndexData_;
85
+ std::string title_;
86
+ std::string content_;
87
+ std::string keywords_;
88
+ uint32_t wordcount_;
89
+ std::optional<GeoPosition> position_;
90
+ };
91
+
92
+ /**
93
+ * Wraps a JS World Item to a zim::writer::Item
94
+ *
95
+ * NOTE: should be initialized on the main thread
96
+ */
97
+ class ItemWrapper : public zim::writer::Item {
98
+ public:
99
+ ItemWrapper(Napi::Env env, Napi::Object item)
100
+ : MAIN_THREAD_ID{}, item_{}, hasIndexDataImpl_{false} {
101
+ MAIN_THREAD_ID = std::this_thread::get_id();
102
+ item_ = Napi::Persistent(item);
103
+
104
+ path_ = item.Get("path").ToString();
105
+ title_ = item.Get("title").ToString();
106
+ mimeType_ = item.Get("mimeType").ToString();
107
+
108
+ const auto hasHints = item.Has("hints");
109
+ hints_ = hasHints ? Object2Hints(item.Get("hints").ToObject())
110
+ : zim::writer::Item::getHints();
111
+
112
+ hasIndexDataImpl_ = item.Has("hasIndexData");
113
+
114
+ if (hasIndexDataImpl_) {
115
+ auto indexDataFuncValue = item.Get("getIndexData");
116
+ if (!indexDataFuncValue.IsFunction()) {
117
+ throw std::runtime_error("getIndexData must be a function");
118
+ }
119
+
120
+ auto indexDataFunc = indexDataFuncValue.As<Napi::Function>();
121
+ indexDataFunc_ = Napi::Persistent(indexDataFunc);
122
+ indexDataTSNF_ = Napi::ThreadSafeFunction::New(
123
+ env, indexDataFunc, "ItemWrapper.indexData", 0, 1);
124
+ }
125
+
126
+ auto providerFuncValue = item.Get("getContentProvider");
127
+ if (!providerFuncValue.IsFunction()) {
128
+ throw std::runtime_error("getContentProvider must be a function");
129
+ }
130
+ auto providerFunc = providerFuncValue.As<Napi::Function>();
131
+ contentProviderFunc_ = Napi::Persistent(providerFunc);
132
+ contentProviderTSNF_ = Napi::ThreadSafeFunction::New(
133
+ env, providerFunc, "ItemWrapper.contentProvider", 5, 1);
134
+ }
135
+
136
+ ~ItemWrapper() {
137
+ if (hasIndexDataImpl_) {
138
+ indexDataTSNF_.Release();
139
+ }
140
+ contentProviderTSNF_.Release();
141
+ }
142
+
143
+ std::string getPath() const override { return path_; }
144
+
145
+ std::string getTitle() const override { return title_; }
146
+
147
+ std::string getMimeType() const override { return mimeType_; }
148
+
149
+ zim::writer::Hints getHints() const override { return hints_; }
150
+
151
+ std::shared_ptr<zim::writer::IndexData> getIndexData() const override {
152
+ if (!hasIndexDataImpl_) {
153
+ // use default implementation
154
+ return zim::writer::Item::getIndexData();
155
+ }
156
+
157
+ if (MAIN_THREAD_ID == std::this_thread::get_id()) {
158
+ auto data = indexDataFunc_.Call(item_.Value(), {});
159
+ return data.IsObject()
160
+ ? std::make_shared<IndexDataWrapper>(data.ToObject())
161
+ : nullptr;
162
+ }
163
+
164
+ // called from a thread
165
+ using IndexDataWrapperPtr = std::shared_ptr<IndexDataWrapper>;
166
+ std::promise<IndexDataWrapperPtr> promise;
167
+ auto future = promise.get_future();
168
+
169
+ auto callback = [&promise, this](Napi::Env env, Napi::Function idxFunc) {
170
+ auto data = idxFunc.Call(item_.Value(), {});
171
+ promise.set_value(
172
+ data.IsObject() ? std::make_shared<IndexDataWrapper>(data.ToObject())
173
+ : nullptr);
174
+ };
175
+
176
+ auto status = indexDataTSNF_.BlockingCall(callback);
177
+ if (status != napi_ok) {
178
+ throw std::runtime_error("Error calling indexData ThreadSafeFunction");
179
+ }
180
+
181
+ return future.get();
182
+ }
183
+
184
+ /**
185
+ * ContentProvider is dynamic and must be created on the main javascript
186
+ * thread.
187
+ */
188
+ std::unique_ptr<zim::writer::ContentProvider> getContentProvider()
189
+ const override {
190
+ if (MAIN_THREAD_ID == std::this_thread::get_id()) {
191
+ auto env = contentProviderFunc_.Env();
192
+ auto provider = contentProviderFunc_.Call(item_.Value(), {});
193
+ if (provider.IsObject()) {
194
+ return std::make_unique<ContentProviderWrapper>(env,
195
+ provider.ToObject());
196
+ } else if (provider.IsNull() || provider.IsUndefined()) {
197
+ return nullptr;
198
+ }
199
+
200
+ throw std::runtime_error(
201
+ "getContentProvider must return an object or null");
202
+ }
203
+
204
+ using ContentProviderWrapperPtr = std::unique_ptr<ContentProviderWrapper>;
205
+ std::promise<ContentProviderWrapperPtr> promise;
206
+ auto future = promise.get_future();
207
+
208
+ auto callback = [&promise, this](Napi::Env env,
209
+ Napi::Function providerFunc) {
210
+ auto provider = providerFunc.Call(item_.Value(), {});
211
+ if (provider.IsObject()) {
212
+ auto ptr =
213
+ std::make_unique<ContentProviderWrapper>(env, provider.ToObject());
214
+ promise.set_value(std::move(ptr));
215
+ } else if (provider.IsNull() || provider.IsUndefined()) {
216
+ promise.set_value(nullptr);
217
+ } else {
218
+ throw std::runtime_error(
219
+ "getContentProvider must return an object or null");
220
+ }
221
+ };
222
+
223
+ auto status = contentProviderTSNF_.BlockingCall(callback);
224
+ if (status != napi_ok) {
225
+ throw std::runtime_error(
226
+ "Error calling contentProvider ThreadSafeFunction");
227
+ }
228
+
229
+ return future.get();
230
+ }
231
+
232
+ private:
233
+ std::thread::id MAIN_THREAD_ID;
234
+ // js world reference, could be an ObjectWrap provider or custom js object
235
+ Napi::ObjectReference item_;
236
+
237
+ std::string path_;
238
+ std::string title_;
239
+ std::string mimeType_;
240
+ zim::writer::Hints hints_;
241
+ bool hasIndexDataImpl_;
242
+
243
+ Napi::FunctionReference indexDataFunc_;
244
+ Napi::ThreadSafeFunction indexDataTSNF_;
245
+ Napi::FunctionReference contentProviderFunc_;
246
+ Napi::ThreadSafeFunction contentProviderTSNF_;
247
+ };
248
+
249
+ class StringItem : public Napi::ObjectWrap<StringItem> {
250
+ public:
251
+ explicit StringItem(const Napi::CallbackInfo &info)
252
+ : Napi::ObjectWrap<StringItem>(info), item_{nullptr} {
253
+ auto env = info.Env();
254
+ if (info.Length() < 5) {
255
+ throw Napi::Error::New(env,
256
+ "StringItem requires arguments (path, mimetype, "
257
+ "title, hints, content)");
258
+ }
259
+
260
+ try {
261
+ auto path = info[0].ToString().Utf8Value();
262
+ auto mimetype = info[1].ToString().Utf8Value();
263
+ auto title = info[2].ToString().Utf8Value();
264
+ auto hints = Object2Hints(info[3].ToObject());
265
+
266
+ const auto &&cval = info[4];
267
+ std::string content;
268
+
269
+ if (cval.IsArrayBuffer()) { // handle ArrayBuffer
270
+ auto buf = cval.As<Napi::ArrayBuffer>();
271
+ auto size = buf.ByteLength();
272
+ content = std::string(reinterpret_cast<const char *>(buf.Data()), size);
273
+ } else if (cval.IsBuffer()) { // handle Buffer
274
+ auto buf = cval.As<Napi::Buffer<char>>();
275
+ auto size = buf.Length();
276
+ content = std::string(reinterpret_cast<const char *>(buf.Data()), size);
277
+ } else {
278
+ content = cval.ToString().Utf8Value();
279
+ }
280
+
281
+ item_ = zim::writer::StringItem::create(path, mimetype, title, hints,
282
+ content);
283
+ } catch (const std::exception &e) {
284
+ throw Napi::Error::New(env, e.what());
285
+ }
286
+ }
287
+
288
+ std::shared_ptr<zim::writer::StringItem> getItem() { return item_; }
289
+
290
+ Napi::Value getPath(const Napi::CallbackInfo &info) {
291
+ try {
292
+ return Napi::Value::From(info.Env(), item_->getPath());
293
+ } catch (const std::exception &err) {
294
+ throw Napi::Error::New(info.Env(), err.what());
295
+ }
296
+ }
297
+
298
+ Napi::Value getTitle(const Napi::CallbackInfo &info) {
299
+ try {
300
+ return Napi::Value::From(info.Env(), item_->getTitle());
301
+ } catch (const std::exception &err) {
302
+ throw Napi::Error::New(info.Env(), err.what());
303
+ }
304
+ }
305
+
306
+ Napi::Value getMimeType(const Napi::CallbackInfo &info) {
307
+ try {
308
+ return Napi::Value::From(info.Env(), item_->getMimeType());
309
+ } catch (const std::exception &err) {
310
+ throw Napi::Error::New(info.Env(), err.what());
311
+ }
312
+ }
313
+
314
+ Napi::Value getHints(const Napi::CallbackInfo &info) {
315
+ try {
316
+ auto env = info.Env();
317
+ auto hints = item_->getHints();
318
+ auto obj = Napi::Object::New(env);
319
+ if (hints.find(zim::writer::COMPRESS) != hints.end()) {
320
+ obj.Set("COMPRESS",
321
+ Napi::Value::From(env, hints[zim::writer::COMPRESS]));
322
+ }
323
+ if (hints.find(zim::writer::FRONT_ARTICLE) != hints.end()) {
324
+ obj.Set("FRONT_ARTICLE",
325
+ Napi::Value::From(env, hints[zim::writer::FRONT_ARTICLE]));
326
+ }
327
+ return obj;
328
+ } catch (const std::exception &err) {
329
+ throw Napi::Error::New(info.Env(), err.what());
330
+ }
331
+ }
332
+
333
+ Napi::Value getContentProvider(const Napi::CallbackInfo &info) {
334
+ try {
335
+ return StringProvider::New(info.Env(), item_->getContentProvider());
336
+ } catch (const std::exception &err) {
337
+ throw Napi::Error::New(info.Env(), err.what());
338
+ }
339
+ }
340
+
341
+ // TODO(kelvinhammond): implement getIndexData for StringItem and FileItem
342
+
343
+ static void Init(Napi::Env env, Napi::Object exports,
344
+ ModuleConstructors &constructors) {
345
+ Napi::HandleScope scope(env);
346
+ Napi::Function func =
347
+ DefineClass(env, "StringItem",
348
+ {
349
+ InstanceAccessor<&StringItem::getPath>("path"),
350
+ InstanceAccessor<&StringItem::getTitle>("title"),
351
+ InstanceAccessor<&StringItem::getMimeType>("mimeType"),
352
+ InstanceMethod<&StringItem::getContentProvider>(
353
+ "getContentProvider"),
354
+ InstanceAccessor<&StringItem::getHints>("hints"),
355
+ });
356
+
357
+ exports.Set("StringItem", func);
358
+ constructors.stringItem = Napi::Persistent(func);
359
+ }
360
+
361
+ private:
362
+ std::shared_ptr<zim::writer::StringItem> item_;
363
+ };
364
+
365
+ class FileItem : public Napi::ObjectWrap<FileItem> {
366
+ public:
367
+ explicit FileItem(const Napi::CallbackInfo &info)
368
+ : Napi::ObjectWrap<FileItem>(info), item_{nullptr} {
369
+ auto env = info.Env();
370
+ if (info.Length() < 5) {
371
+ throw Napi::Error::New(env,
372
+ "FileItem requires arguments (path, mimetype, "
373
+ "title, hints, content)");
374
+ }
375
+
376
+ try {
377
+ auto path = info[0].ToString();
378
+ auto mimetype = info[1].ToString();
379
+ auto title = info[2].ToString();
380
+ auto hints = Object2Hints(info[3].ToObject());
381
+ auto filepath = info[4].ToString();
382
+ item_ = std::make_shared<zim::writer::FileItem>(path, mimetype, title,
383
+ hints, filepath);
384
+ } catch (const std::exception &e) {
385
+ throw Napi::Error::New(env, e.what());
386
+ }
387
+ }
388
+
389
+ std::shared_ptr<zim::writer::FileItem> getItem() { return item_; }
390
+
391
+ Napi::Value getPath(const Napi::CallbackInfo &info) {
392
+ try {
393
+ return Napi::Value::From(info.Env(), item_->getPath());
394
+ } catch (const std::exception &err) {
395
+ throw Napi::Error::New(info.Env(), err.what());
396
+ }
397
+ }
398
+
399
+ Napi::Value getTitle(const Napi::CallbackInfo &info) {
400
+ try {
401
+ return Napi::Value::From(info.Env(), item_->getTitle());
402
+ } catch (const std::exception &err) {
403
+ throw Napi::Error::New(info.Env(), err.what());
404
+ }
405
+ }
406
+
407
+ Napi::Value getMimeType(const Napi::CallbackInfo &info) {
408
+ try {
409
+ return Napi::Value::From(info.Env(), item_->getMimeType());
410
+ } catch (const std::exception &err) {
411
+ throw Napi::Error::New(info.Env(), err.what());
412
+ }
413
+ }
414
+
415
+ Napi::Value getHints(const Napi::CallbackInfo &info) {
416
+ try {
417
+ auto env = info.Env();
418
+ auto hints = item_->getHints();
419
+ auto obj = Napi::Object::New(env);
420
+ if (hints.find(zim::writer::COMPRESS) != hints.end()) {
421
+ obj.Set("COMPRESS",
422
+ Napi::Value::From(env, hints[zim::writer::COMPRESS]));
423
+ }
424
+ if (hints.find(zim::writer::FRONT_ARTICLE) != hints.end()) {
425
+ obj.Set("FRONT_ARTICLE",
426
+ Napi::Value::From(env, hints[zim::writer::FRONT_ARTICLE]));
427
+ }
428
+ return obj;
429
+ } catch (const std::exception &err) {
430
+ throw Napi::Error::New(info.Env(), err.what());
431
+ }
432
+ }
433
+
434
+ Napi::Value getContentProvider(const Napi::CallbackInfo &info) {
435
+ try {
436
+ return FileProvider::New(info.Env(), item_->getContentProvider());
437
+ } catch (const std::exception &err) {
438
+ throw Napi::Error::New(info.Env(), err.what());
439
+ }
440
+ }
441
+
442
+ static void Init(Napi::Env env, Napi::Object exports,
443
+ ModuleConstructors &constructors) {
444
+ Napi::HandleScope scope(env);
445
+ Napi::Function func = DefineClass(
446
+ env, "FileItem",
447
+ {
448
+ InstanceAccessor<&FileItem::getPath>("path"),
449
+ InstanceAccessor<&FileItem::getTitle>("title"),
450
+ InstanceAccessor<&FileItem::getMimeType>("mimeType"),
451
+ InstanceMethod<&FileItem::getContentProvider>("getContentProvider"),
452
+ InstanceAccessor<&FileItem::getHints>("hints"),
453
+ });
454
+
455
+ exports.Set("FileItem", func);
456
+ constructors.fileItem = Napi::Persistent(func);
457
+ }
458
+
459
+ private:
460
+ std::shared_ptr<zim::writer::FileItem> item_;
461
+ };
462
+
package/tsconfig.json CHANGED
@@ -2,16 +2,14 @@
2
2
  "compilerOptions": {
3
3
  "module": "commonjs",
4
4
  "lib": [
5
- "es2015"
5
+ "es6"
6
6
  ],
7
+ "allowJs": true,
7
8
  "declaration": true,
8
9
  "noImplicitAny": true,
9
10
  "outDir": "dist",
10
11
  "removeComments": false,
11
- "target": "es5",
12
+ "target": "es6",
12
13
  "esModuleInterop": true
13
- },
14
- "files": [
15
- "src/index.ts"
16
- ]
14
+ }
17
15
  }
@@ -1,34 +0,0 @@
1
- export interface ZimCreatorOpts {
2
- fileName: string;
3
- welcome?: string;
4
- compression?: string;
5
- fullTextIndexLanguage?: string;
6
- minChunkSize?: number;
7
- }
8
- export interface ZimMetadata {
9
- Counter?: string;
10
- Creator?: string;
11
- Date?: string;
12
- Description?: string;
13
- Flavour?: string;
14
- Language?: string;
15
- Name?: string;
16
- Publisher?: string;
17
- Tags?: string;
18
- Title?: string;
19
- }
20
- declare class ZimCreator {
21
- tmpDir: string;
22
- _creator: any;
23
- fileName: string;
24
- compression: string;
25
- articleCounter: {
26
- [mimeType: string]: number;
27
- };
28
- constructor(opts: ZimCreatorOpts, metadata?: ZimMetadata);
29
- get isAlive(): boolean;
30
- addArticle(article: any): Promise<any>;
31
- setMetadata(metadata: ZimMetadata): Promise<void>;
32
- finalise(): Promise<void>;
33
- }
34
- export { ZimCreator };
@@ -1,177 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
- return new (P || (P = Promise))(function (resolve, reject) {
24
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
- step((generator = generator.apply(thisArg, _arguments || [])).next());
28
- });
29
- };
30
- var __generator = (this && this.__generator) || function (thisArg, body) {
31
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
32
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
33
- function verb(n) { return function (v) { return step([n, v]); }; }
34
- function step(op) {
35
- if (f) throw new TypeError("Generator is already executing.");
36
- while (_) try {
37
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
38
- if (y = 0, t) op = [op[0] & 2, t.value];
39
- switch (op[0]) {
40
- case 0: case 1: t = op; break;
41
- case 4: _.label++; return { value: op[1], done: false };
42
- case 5: _.label++; y = op[1]; op = [0]; continue;
43
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
44
- default:
45
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
46
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
47
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
48
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
49
- if (t[2]) _.ops.pop();
50
- _.trys.pop(); continue;
51
- }
52
- op = body.call(thisArg, _);
53
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
54
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
55
- }
56
- };
57
- Object.defineProperty(exports, "__esModule", { value: true });
58
- exports.ZimCreator = void 0;
59
- var fs_1 = require("fs");
60
- var mime = __importStar(require("mime"));
61
- var rimraf = __importStar(require("rimraf"));
62
- var zim_1 = require("./zim");
63
- var ZimCreator = /** @class */ (function () {
64
- function ZimCreator(opts, metadata) {
65
- if (metadata === void 0) { metadata = {}; }
66
- this.articleCounter = {};
67
- this.fileName = opts.fileName;
68
- this.compression = opts.compression || 'lzma';
69
- this.articleCounter = {};
70
- this.tmpDir = this.fileName.split('.').slice(0, -1).join('.') + '.tmp';
71
- var metadataDefaults = {
72
- Date: (new Date()).toJSON().split('T')[0],
73
- Language: 'eng',
74
- };
75
- metadata = Object.assign(metadataDefaults, metadata);
76
- try {
77
- var statRes = fs_1.statSync(this.tmpDir);
78
- console.info("Tmp directory already exists, deleting [" + this.tmpDir + "]");
79
- rimraf.sync(this.tmpDir);
80
- }
81
- catch (err) {
82
- // noop
83
- }
84
- var _a = opts.welcome, welcome = _a === void 0 ? '' : _a, _b = opts.fullTextIndexLanguage, fullTextIndexLanguage = _b === void 0 ? '' : _b, _c = opts.minChunkSize, minChunkSize = _c === void 0 ? 2048 : _c;
85
- this._creator = new zim_1.ZimCreatorWrapper({
86
- fileName: this.fileName,
87
- mainPage: welcome,
88
- compression: this.compression,
89
- fullTextIndexLanguage: fullTextIndexLanguage,
90
- minChunkSize: minChunkSize
91
- });
92
- this.setMetadata(metadata);
93
- }
94
- Object.defineProperty(ZimCreator.prototype, "isAlive", {
95
- get: function () {
96
- return !!this._creator;
97
- },
98
- enumerable: false,
99
- configurable: true
100
- });
101
- ZimCreator.prototype.addArticle = function (article) {
102
- var _a;
103
- return __awaiter(this, void 0, void 0, function () {
104
- return __generator(this, function (_b) {
105
- switch (_b.label) {
106
- case 0:
107
- if (!this.isAlive)
108
- throw new Error("This Creator has been destroyed");
109
- if (!article.mimeType)
110
- article.mimeType = mime.getType(article.url) || 'text/plain';
111
- return [4 /*yield*/, this._creator.addArticle(article)];
112
- case 1:
113
- _b.sent();
114
- if (!article.redirectUrl) {
115
- this.articleCounter[article.mimeType] = (_a = this.articleCounter[article.mimeType]) !== null && _a !== void 0 ? _a : 0;
116
- this.articleCounter[article.mimeType] += 1;
117
- }
118
- return [2 /*return*/, article];
119
- }
120
- });
121
- });
122
- };
123
- ZimCreator.prototype.setMetadata = function (metadata) {
124
- return __awaiter(this, void 0, void 0, function () {
125
- var keys, _i, keys_1, key, content, article;
126
- return __generator(this, function (_a) {
127
- switch (_a.label) {
128
- case 0:
129
- if (!this.isAlive)
130
- throw new Error("This Creator has been destroyed");
131
- keys = Object.keys(metadata).filter(function (key) { return metadata[key]; });
132
- _i = 0, keys_1 = keys;
133
- _a.label = 1;
134
- case 1:
135
- if (!(_i < keys_1.length)) return [3 /*break*/, 4];
136
- key = keys_1[_i];
137
- content = metadata[key];
138
- article = new zim_1.ZimArticle({ url: key, data: content, ns: 'M' });
139
- return [4 /*yield*/, this.addArticle(article)];
140
- case 2:
141
- _a.sent();
142
- _a.label = 3;
143
- case 3:
144
- _i++;
145
- return [3 /*break*/, 1];
146
- case 4: return [2 /*return*/];
147
- }
148
- });
149
- });
150
- };
151
- ZimCreator.prototype.finalise = function () {
152
- return __awaiter(this, void 0, void 0, function () {
153
- var counterString;
154
- var _this = this;
155
- return __generator(this, function (_a) {
156
- switch (_a.label) {
157
- case 0:
158
- if (!this.isAlive)
159
- throw new Error("This Creator has been destroyed");
160
- counterString = Object.keys(this.articleCounter)
161
- .map(function (mimeType) { return mimeType + "=" + _this.articleCounter[mimeType]; })
162
- .join(';');
163
- return [4 /*yield*/, this.setMetadata({ Counter: counterString })];
164
- case 1:
165
- _a.sent();
166
- return [4 /*yield*/, this._creator.finalise()];
167
- case 2:
168
- _a.sent();
169
- this._creator = null;
170
- return [2 /*return*/];
171
- }
172
- });
173
- });
174
- };
175
- return ZimCreator;
176
- }());
177
- exports.ZimCreator = ZimCreator;