shamela 1.0.3 → 1.0.4
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 -26
- package/dist/main.js +241 -223
- package/dist/main.js.map +1 -1
- package/package.json +20 -21
package/README.md
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
# Shamela
|
|
2
2
|
|
|
3
|
-
[](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e)
|
|
3
|
+
[](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e)
|
|
4
|
+
[](https://github.com/ragaeeb/shamela/actions/workflows/e2e.yml)
|
|
5
|
+
[](https://github.com/ragaeeb/shamela/actions/workflows/build.yml) 
|
|
6
|
+

|
|
7
|
+
[](https://codecov.io/gh/ragaeeb/shamela)
|
|
8
|
+
[](https://bundlejs.com/?q=shamela%401.0.5)
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
4
14
|
|
|
5
15
|
A `NodeJS` library for accessing and downloading Maktabah Shamela v4 APIs. This library provides easy-to-use functions to interact with the Shamela API, download master and book databases, and retrieve book data programmatically.
|
|
6
16
|
|
|
7
17
|
## Table of Contents
|
|
8
18
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Environment Variables](#environment-variables)
|
|
21
|
+
- [Usage](#usage)
|
|
22
|
+
- [Getting Started](#getting-started)
|
|
23
|
+
- [API Functions](#api-functions)
|
|
24
|
+
- [getMasterMetadata](#getmastermetadata)
|
|
25
|
+
- [downloadMasterDatabase](#downloadmasterdatabase)
|
|
26
|
+
- [getBookMetadata](#getbookmetadata)
|
|
27
|
+
- [downloadBook](#downloadbook)
|
|
28
|
+
- [getBook](#getbook)
|
|
29
|
+
- [Examples](#examples)
|
|
30
|
+
- [Downloading the Master Database](#downloading-the-master-database)
|
|
31
|
+
- [Downloading a Book](#downloading-a-book)
|
|
32
|
+
- [Retrieving Book Data](#retrieving-book-data)
|
|
33
|
+
- [Testing](#testing)
|
|
34
|
+
- [License](#license)
|
|
25
35
|
|
|
26
36
|
## Installation
|
|
27
37
|
|
|
@@ -77,7 +87,7 @@ getMasterMetadata(version?: number): Promise<GetMasterMetadataResponsePayload>
|
|
|
77
87
|
|
|
78
88
|
```
|
|
79
89
|
|
|
80
|
-
-
|
|
90
|
+
- version (optional): The version number of the master database you want to fetch.
|
|
81
91
|
|
|
82
92
|
Example:
|
|
83
93
|
|
|
@@ -94,9 +104,9 @@ downloadMasterDatabase(options: DownloadMasterOptions): Promise<string>
|
|
|
94
104
|
|
|
95
105
|
```
|
|
96
106
|
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
107
|
+
- options: An object containing:
|
|
108
|
+
- masterMetadata (optional): The metadata obtained from getMasterMetadata.
|
|
109
|
+
- outputFile: An object specifying the output path.
|
|
100
110
|
|
|
101
111
|
Example:
|
|
102
112
|
|
|
@@ -114,10 +124,10 @@ Fetches metadata for a specific book.
|
|
|
114
124
|
getBookMetadata(id: number, options?: GetBookMetadataOptions): Promise<GetBookMetadataResponsePayload>
|
|
115
125
|
```
|
|
116
126
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
127
|
+
- id: The ID of the book.
|
|
128
|
+
- options (optional): An object containing:
|
|
129
|
+
- majorVersion: The major version of the book.
|
|
130
|
+
- minorVersion: The minor version of the book.
|
|
121
131
|
|
|
122
132
|
Example:
|
|
123
133
|
|
|
@@ -135,7 +145,7 @@ Retrieves the data of a book as a JavaScript object.
|
|
|
135
145
|
getBook(id: number): Promise<BookData>
|
|
136
146
|
```
|
|
137
147
|
|
|
138
|
-
-
|
|
148
|
+
- id: The ID of the book.
|
|
139
149
|
|
|
140
150
|
Example:
|
|
141
151
|
|
package/dist/main.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {createClient as $
|
|
2
|
-
import {promises as $
|
|
3
|
-
import $
|
|
4
|
-
import $
|
|
5
|
-
import {URL as $
|
|
6
|
-
import $
|
|
7
|
-
import $
|
|
8
|
-
import $
|
|
9
|
-
import $
|
|
10
|
-
import {pipeline as $
|
|
11
|
-
import $
|
|
12
|
-
import {Buffer as $
|
|
1
|
+
import {createClient as $SK0tW$createClient} from "@libsql/client";
|
|
2
|
+
import {promises as $SK0tW$promises, createWriteStream as $SK0tW$createWriteStream} from "fs";
|
|
3
|
+
import $SK0tW$path from "path";
|
|
4
|
+
import $SK0tW$process from "process";
|
|
5
|
+
import {URL as $SK0tW$URL, URLSearchParams as $SK0tW$URLSearchParams} from "url";
|
|
6
|
+
import $SK0tW$pino from "pino";
|
|
7
|
+
import $SK0tW$pinopretty from "pino-pretty";
|
|
8
|
+
import $SK0tW$https from "https";
|
|
9
|
+
import $SK0tW$os from "os";
|
|
10
|
+
import {pipeline as $SK0tW$pipeline} from "stream/promises";
|
|
11
|
+
import $SK0tW$unzipper from "unzipper";
|
|
12
|
+
import {Buffer as $SK0tW$Buffer} from "buffer";
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
@@ -19,44 +19,50 @@ import {Buffer as $5oumB$Buffer} from "buffer";
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
const $
|
|
22
|
+
const $526b48a37e8a8ec6$var$stream = (0, $SK0tW$pinopretty)({
|
|
23
23
|
colorize: true
|
|
24
24
|
});
|
|
25
|
-
const $
|
|
25
|
+
const $526b48a37e8a8ec6$var$logger = (0, $SK0tW$pino)({
|
|
26
26
|
base: {
|
|
27
27
|
pid: undefined,
|
|
28
28
|
hostname: undefined
|
|
29
29
|
},
|
|
30
|
-
level: (0, $
|
|
31
|
-
}, $
|
|
32
|
-
var $
|
|
30
|
+
level: (0, $SK0tW$process).env.LOG_LEVEL || 'info'
|
|
31
|
+
}, $526b48a37e8a8ec6$var$stream);
|
|
32
|
+
var $526b48a37e8a8ec6$export$2e2bcd8739ae039 = $526b48a37e8a8ec6$var$logger;
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
const $
|
|
36
|
-
const { rows: tables } = await db.execute(`SELECT name FROM ${dbName}.sqlite_master WHERE type='table'`);
|
|
37
|
-
return tables
|
|
35
|
+
const $26460f21c4456828$export$1d57574773c8bc58 = async (db, dbName)=>{
|
|
36
|
+
const { rows: tables } = await db.execute(`SELECT name,sql FROM ${dbName}.sqlite_master WHERE type='table'`);
|
|
37
|
+
return tables.map((row)=>{
|
|
38
|
+
const fields = row.sql.split(', ').map((field)=>field.split(' ')[0]);
|
|
39
|
+
return {
|
|
40
|
+
fields: fields,
|
|
41
|
+
name: row.name
|
|
42
|
+
};
|
|
43
|
+
});
|
|
38
44
|
};
|
|
39
|
-
const $
|
|
45
|
+
const $26460f21c4456828$export$3274d151f0598f1 = async (client, table)=>{
|
|
40
46
|
const { rows: rows } = await client.execute(`SELECT * FROM ${table}`);
|
|
41
47
|
return rows;
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
|
|
45
|
-
const $
|
|
46
|
-
const $
|
|
47
|
-
const $
|
|
51
|
+
const $746504ca27eabe49$var$MAIN_DB_ALIAS = 'main';
|
|
52
|
+
const $746504ca27eabe49$export$ee56083bb7df7ecc = (dbFile, alias)=>`ATTACH DATABASE '${dbFile}' AS ${alias}`;
|
|
53
|
+
const $746504ca27eabe49$export$1f75c01d8a920a35 = (patchAlias, tableName, aslAlias = $746504ca27eabe49$var$MAIN_DB_ALIAS)=>`
|
|
48
54
|
UPDATE ${aslAlias}.${tableName}
|
|
49
|
-
SET content = ${$
|
|
50
|
-
part = ${$
|
|
51
|
-
page = ${$
|
|
52
|
-
number = ${$
|
|
55
|
+
SET content = ${$746504ca27eabe49$var$updatePageColumn('content', aslAlias, patchAlias)},
|
|
56
|
+
part = ${$746504ca27eabe49$var$updatePageColumn('part', aslAlias, patchAlias)},
|
|
57
|
+
page = ${$746504ca27eabe49$var$updatePageColumn('page', aslAlias, patchAlias)},
|
|
58
|
+
number = ${$746504ca27eabe49$var$updatePageColumn('number', aslAlias, patchAlias)}
|
|
53
59
|
WHERE EXISTS (
|
|
54
60
|
SELECT 1
|
|
55
61
|
FROM ${patchAlias}.${tableName}
|
|
56
62
|
WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id
|
|
57
63
|
);
|
|
58
64
|
`;
|
|
59
|
-
const $
|
|
65
|
+
const $746504ca27eabe49$var$updateTitleColumn = (columnName, aslAlias, patchAlias)=>`
|
|
60
66
|
(SELECT CASE
|
|
61
67
|
WHEN ${patchAlias}.title.${columnName} != '#' THEN ${patchAlias}.title.${columnName}
|
|
62
68
|
ELSE ${aslAlias}.title.${columnName}
|
|
@@ -64,20 +70,20 @@ const $e6f751831b705ed8$var$updateTitleColumn = (columnName, aslAlias, patchAlia
|
|
|
64
70
|
FROM ${patchAlias}.title
|
|
65
71
|
WHERE ${aslAlias}.title.id = ${patchAlias}.title.id)
|
|
66
72
|
`;
|
|
67
|
-
const $
|
|
73
|
+
const $746504ca27eabe49$export$a38d1618b943c74f = (patchAlias, tableName, aslAlias = $746504ca27eabe49$var$MAIN_DB_ALIAS)=>`
|
|
68
74
|
UPDATE ${aslAlias}.${tableName}
|
|
69
|
-
SET content = ${$
|
|
70
|
-
page = ${$
|
|
71
|
-
parent = ${$
|
|
75
|
+
SET content = ${$746504ca27eabe49$var$updateTitleColumn('content', aslAlias, patchAlias)},
|
|
76
|
+
page = ${$746504ca27eabe49$var$updateTitleColumn('page', aslAlias, patchAlias)},
|
|
77
|
+
parent = ${$746504ca27eabe49$var$updateTitleColumn('parent', aslAlias, patchAlias)}
|
|
72
78
|
WHERE EXISTS (
|
|
73
79
|
SELECT 1
|
|
74
80
|
FROM ${patchAlias}.${tableName}
|
|
75
81
|
WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id
|
|
76
82
|
);
|
|
77
83
|
`;
|
|
78
|
-
const $
|
|
79
|
-
const $
|
|
80
|
-
const $
|
|
84
|
+
const $746504ca27eabe49$export$33bbb3ec7652e187 = (name, fields)=>`CREATE TABLE IF NOT EXISTS ${name} (${fields.join(', ')})`;
|
|
85
|
+
const $746504ca27eabe49$export$7fec5208c714b262 = (alias)=>`DETACH DATABASE ${alias}`;
|
|
86
|
+
const $746504ca27eabe49$var$updatePageColumn = (columnName, aslAlias, patchAlias)=>`
|
|
81
87
|
(SELECT CASE
|
|
82
88
|
WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}
|
|
83
89
|
ELSE ${aslAlias}.page.${columnName}
|
|
@@ -85,85 +91,97 @@ const $e6f751831b705ed8$var$updatePageColumn = (columnName, aslAlias, patchAlias
|
|
|
85
91
|
FROM ${patchAlias}.page
|
|
86
92
|
WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)
|
|
87
93
|
`;
|
|
88
|
-
const $
|
|
94
|
+
const $746504ca27eabe49$export$3ef07b9580a45514 = (table, fieldToValue, isDeleted = false)=>{
|
|
89
95
|
const combinedRecords = {
|
|
90
96
|
...fieldToValue,
|
|
91
|
-
is_deleted: isDeleted ?
|
|
97
|
+
is_deleted: isDeleted ? '1' : '0'
|
|
92
98
|
};
|
|
93
99
|
const sortedKeys = Object.keys(combinedRecords).sort();
|
|
94
100
|
const sortedValues = sortedKeys.map((key)=>combinedRecords[key]);
|
|
95
101
|
return `INSERT INTO ${table} (${sortedKeys.toString()}) VALUES (${sortedValues.map((val)=>{
|
|
96
|
-
if (val === null) return
|
|
97
|
-
return typeof val ===
|
|
102
|
+
if (val === null) return 'NULL';
|
|
103
|
+
return typeof val === 'string' ? `'${val}'` : val;
|
|
98
104
|
}).toString()})`;
|
|
99
105
|
};
|
|
100
106
|
|
|
101
107
|
|
|
102
|
-
var $
|
|
103
|
-
(function(Tables) {
|
|
108
|
+
var $e5a23c058b2763fa$export$a17a6870a08b950e = /*#__PURE__*/ function(Tables) {
|
|
104
109
|
Tables["Authors"] = "authors";
|
|
105
110
|
Tables["Books"] = "books";
|
|
106
111
|
Tables["Categories"] = "categories";
|
|
107
112
|
Tables["Page"] = "page";
|
|
108
113
|
Tables["Title"] = "title";
|
|
109
|
-
|
|
114
|
+
return Tables;
|
|
115
|
+
}({});
|
|
110
116
|
|
|
111
117
|
|
|
112
|
-
const $
|
|
113
|
-
const $
|
|
114
|
-
const $
|
|
115
|
-
const statements = [];
|
|
116
|
-
if (tables.find((t)=>t.name === (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page)) {
|
|
117
|
-
statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE id IN (SELECT id FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0')`);
|
|
118
|
-
statements.push((0, $e6f751831b705ed8$export$1f75c01d8a920a35)($2a3b237385dd2cff$var$PATCH_DB_ALIAS, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page));
|
|
119
|
-
} else statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0'`);
|
|
120
|
-
return statements;
|
|
121
|
-
};
|
|
122
|
-
const $2a3b237385dd2cff$var$getTitlesToCopy = (tables)=>{
|
|
118
|
+
const $d7a7877f07ff6c69$var$PATCH_DB_ALIAS = 'patch';
|
|
119
|
+
const $d7a7877f07ff6c69$var$ASL_DB_ALIAS = 'asl';
|
|
120
|
+
const $d7a7877f07ff6c69$var$buildCopyStatements = (patchTables, aslTables, table, fields, patchQuery)=>{
|
|
123
121
|
const statements = [];
|
|
124
|
-
if (
|
|
125
|
-
statements.push(`INSERT INTO main.${
|
|
126
|
-
statements.push(
|
|
127
|
-
} else
|
|
122
|
+
if (patchTables.find((t)=>t.name === table)) {
|
|
123
|
+
statements.push(`INSERT INTO main.${table} SELECT ${fields.join(',')} FROM ${$d7a7877f07ff6c69$var$ASL_DB_ALIAS}.${table} WHERE id IN (SELECT id FROM ${$d7a7877f07ff6c69$var$PATCH_DB_ALIAS}.${table} WHERE is_deleted='0')`);
|
|
124
|
+
statements.push(patchQuery);
|
|
125
|
+
} else {
|
|
126
|
+
let copyStatement = `INSERT INTO main.${table} SELECT ${fields.join(',')} FROM ${$d7a7877f07ff6c69$var$ASL_DB_ALIAS}.${table}`;
|
|
127
|
+
if (aslTables.find((t)=>t.name === table)?.fields.includes('is_deleted')) copyStatement += ` WHERE is_deleted='0'`;
|
|
128
|
+
statements.push(copyStatement);
|
|
129
|
+
}
|
|
128
130
|
return statements;
|
|
129
131
|
};
|
|
130
|
-
const $
|
|
131
|
-
|
|
132
|
-
(0, $
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
const $d7a7877f07ff6c69$export$a8b8e03e6bbe5473 = async (db, aslDB, patchDB)=>{
|
|
133
|
+
await Promise.all([
|
|
134
|
+
db.execute((0, $746504ca27eabe49$export$ee56083bb7df7ecc)(aslDB, $d7a7877f07ff6c69$var$ASL_DB_ALIAS)),
|
|
135
|
+
db.execute((0, $746504ca27eabe49$export$ee56083bb7df7ecc)(patchDB, $d7a7877f07ff6c69$var$PATCH_DB_ALIAS))
|
|
136
|
+
]);
|
|
137
|
+
const [patchTables, aslTables] = await Promise.all([
|
|
138
|
+
(0, $26460f21c4456828$export$1d57574773c8bc58)(db, $d7a7877f07ff6c69$var$PATCH_DB_ALIAS),
|
|
139
|
+
(0, $26460f21c4456828$export$1d57574773c8bc58)(db, $d7a7877f07ff6c69$var$ASL_DB_ALIAS)
|
|
140
|
+
]);
|
|
141
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).debug({
|
|
142
|
+
aslTables: aslTables,
|
|
143
|
+
patchTables: patchTables
|
|
138
144
|
}, `Applying patches for...`);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
await db.batch([
|
|
146
|
+
...$d7a7877f07ff6c69$var$buildCopyStatements(patchTables, aslTables, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Page, [
|
|
147
|
+
'id',
|
|
148
|
+
'content',
|
|
149
|
+
'part',
|
|
150
|
+
'page',
|
|
151
|
+
'number'
|
|
152
|
+
], (0, $746504ca27eabe49$export$1f75c01d8a920a35)($d7a7877f07ff6c69$var$PATCH_DB_ALIAS, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Page)),
|
|
153
|
+
...$d7a7877f07ff6c69$var$buildCopyStatements(patchTables, aslTables, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Title, [
|
|
154
|
+
'id',
|
|
155
|
+
'content',
|
|
156
|
+
'page',
|
|
157
|
+
'parent'
|
|
158
|
+
], (0, $746504ca27eabe49$export$a38d1618b943c74f)($d7a7877f07ff6c69$var$PATCH_DB_ALIAS, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Title))
|
|
159
|
+
]);
|
|
160
|
+
return db.batch([
|
|
161
|
+
(0, $746504ca27eabe49$export$7fec5208c714b262)($d7a7877f07ff6c69$var$ASL_DB_ALIAS),
|
|
162
|
+
(0, $746504ca27eabe49$export$7fec5208c714b262)($d7a7877f07ff6c69$var$PATCH_DB_ALIAS)
|
|
163
|
+
]);
|
|
146
164
|
};
|
|
147
|
-
const $
|
|
148
|
-
await db.execute((0, $
|
|
149
|
-
const tables = await (0, $
|
|
150
|
-
(0, $
|
|
165
|
+
const $d7a7877f07ff6c69$export$61101aa23c771e7c = async (db, aslDB)=>{
|
|
166
|
+
await db.execute((0, $746504ca27eabe49$export$ee56083bb7df7ecc)(aslDB, $d7a7877f07ff6c69$var$ASL_DB_ALIAS));
|
|
167
|
+
const tables = await (0, $26460f21c4456828$export$1d57574773c8bc58)(db, $d7a7877f07ff6c69$var$ASL_DB_ALIAS);
|
|
168
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).debug({
|
|
151
169
|
tables: tables
|
|
152
170
|
}, `Applying patches for...`);
|
|
153
171
|
await db.batch([
|
|
154
|
-
`INSERT INTO main.${(0, $
|
|
155
|
-
`INSERT INTO main.${(0, $
|
|
172
|
+
`INSERT INTO main.${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$d7a7877f07ff6c69$var$ASL_DB_ALIAS}.${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Title}`,
|
|
173
|
+
`INSERT INTO main.${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$d7a7877f07ff6c69$var$ASL_DB_ALIAS}.${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Page}`
|
|
156
174
|
]);
|
|
157
|
-
return db.execute((0, $
|
|
175
|
+
return db.execute((0, $746504ca27eabe49$export$7fec5208c714b262)($d7a7877f07ff6c69$var$ASL_DB_ALIAS));
|
|
158
176
|
};
|
|
159
|
-
const $
|
|
177
|
+
const $d7a7877f07ff6c69$export$5d28a6b0dd65e4c4 = async (db)=>{
|
|
160
178
|
return db.batch([
|
|
161
179
|
`CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,
|
|
162
180
|
`CREATE TABLE title (id INTEGER PRIMARY KEY, content TEXT, page INTEGER, parent INTEGER)`
|
|
163
181
|
]);
|
|
164
182
|
};
|
|
165
|
-
const $
|
|
166
|
-
const rows = await (0, $
|
|
183
|
+
const $d7a7877f07ff6c69$export$3bd13330ac8e761e = async (db)=>{
|
|
184
|
+
const rows = await (0, $26460f21c4456828$export$3274d151f0598f1)(db, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Page);
|
|
167
185
|
const pages = rows.map((row)=>{
|
|
168
186
|
const { content: content, id: id, number: number, page: page, part: part } = row;
|
|
169
187
|
return {
|
|
@@ -182,8 +200,8 @@ const $2a3b237385dd2cff$export$3bd13330ac8e761e = async (db)=>{
|
|
|
182
200
|
});
|
|
183
201
|
return pages;
|
|
184
202
|
};
|
|
185
|
-
const $
|
|
186
|
-
const rows = await (0, $
|
|
203
|
+
const $d7a7877f07ff6c69$export$8987cf231214301f = async (db)=>{
|
|
204
|
+
const rows = await (0, $26460f21c4456828$export$3274d151f0598f1)(db, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Title);
|
|
187
205
|
const titles = rows.map((row)=>{
|
|
188
206
|
const r = row;
|
|
189
207
|
return {
|
|
@@ -197,10 +215,10 @@ const $2a3b237385dd2cff$export$8987cf231214301f = async (db)=>{
|
|
|
197
215
|
});
|
|
198
216
|
return titles;
|
|
199
217
|
};
|
|
200
|
-
const $
|
|
218
|
+
const $d7a7877f07ff6c69$export$7a171f172be0782e = async (db)=>{
|
|
201
219
|
const [pages, titles] = await Promise.all([
|
|
202
|
-
$
|
|
203
|
-
$
|
|
220
|
+
$d7a7877f07ff6c69$export$3bd13330ac8e761e(db),
|
|
221
|
+
$d7a7877f07ff6c69$export$8987cf231214301f(db)
|
|
204
222
|
]);
|
|
205
223
|
return {
|
|
206
224
|
pages: pages,
|
|
@@ -210,41 +228,41 @@ const $2a3b237385dd2cff$export$7a171f172be0782e = async (db)=>{
|
|
|
210
228
|
|
|
211
229
|
|
|
212
230
|
|
|
213
|
-
const $
|
|
214
|
-
const $
|
|
231
|
+
const $1857efaf39b32304$export$5bc725975f47e62c = 0;
|
|
232
|
+
const $1857efaf39b32304$export$3deaf0b0365f781e = '99999';
|
|
215
233
|
|
|
216
234
|
|
|
217
235
|
|
|
218
236
|
|
|
219
237
|
|
|
220
|
-
const $
|
|
238
|
+
const $09a9521c7a529893$export$b3179f41dfd6e35b = async (db, sourceTables)=>{
|
|
221
239
|
const aliasToPath = sourceTables.reduce((acc, tablePath)=>{
|
|
222
|
-
const { name: name } = (0, $
|
|
240
|
+
const { name: name } = (0, $SK0tW$path).parse(tablePath);
|
|
223
241
|
return {
|
|
224
242
|
...acc,
|
|
225
243
|
[name]: tablePath
|
|
226
244
|
};
|
|
227
245
|
}, {});
|
|
228
|
-
const attachStatements = Object.entries(aliasToPath).map(([alias, dbPath])=>(0, $
|
|
246
|
+
const attachStatements = Object.entries(aliasToPath).map(([alias, dbPath])=>(0, $746504ca27eabe49$export$ee56083bb7df7ecc)(dbPath, alias));
|
|
229
247
|
await db.batch(attachStatements);
|
|
230
248
|
const insertStatements = [
|
|
231
|
-
`INSERT INTO ${(0, $
|
|
232
|
-
`INSERT INTO ${(0, $
|
|
233
|
-
`INSERT INTO ${(0, $
|
|
249
|
+
`INSERT INTO ${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Authors} SELECT id,name,biography,(CASE WHEN death_number = ${(0, $1857efaf39b32304$export$3deaf0b0365f781e)} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,
|
|
250
|
+
`INSERT INTO ${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Books} SELECT id,name,category,type,(CASE WHEN date = ${(0, $1857efaf39b32304$export$3deaf0b0365f781e)} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,
|
|
251
|
+
`INSERT INTO ${(0, $e5a23c058b2763fa$export$a17a6870a08b950e).Categories} SELECT id,name FROM category WHERE is_deleted='0'`
|
|
234
252
|
];
|
|
235
253
|
await db.batch(insertStatements);
|
|
236
|
-
const detachStatements = Object.keys(aliasToPath).map((0, $
|
|
254
|
+
const detachStatements = Object.keys(aliasToPath).map((0, $746504ca27eabe49$export$7fec5208c714b262));
|
|
237
255
|
await db.batch(detachStatements);
|
|
238
256
|
};
|
|
239
|
-
const $
|
|
257
|
+
const $09a9521c7a529893$export$5d28a6b0dd65e4c4 = async (db)=>{
|
|
240
258
|
return db.batch([
|
|
241
259
|
`CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,
|
|
242
260
|
`CREATE TABLE books (id INTEGER PRIMARY KEY, name TEXT, category INTEGER, type INTEGER, date INTEGER, author TEXT, printed INTEGER, major INTEGER, minor INTEGER, bibliography TEXT, hint TEXT, pdf_links TEXT, metadata TEXT)`,
|
|
243
261
|
`CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)`
|
|
244
262
|
]);
|
|
245
263
|
};
|
|
246
|
-
const $
|
|
247
|
-
const rows = await (0, $
|
|
264
|
+
const $09a9521c7a529893$export$b3b931905baa18df = async (db)=>{
|
|
265
|
+
const rows = await (0, $26460f21c4456828$export$3274d151f0598f1)(db, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Authors);
|
|
248
266
|
const authors = rows.map((r)=>({
|
|
249
267
|
...r.biography && {
|
|
250
268
|
biography: r.biography
|
|
@@ -257,12 +275,12 @@ const $e19722dabbedc0a6$export$b3b931905baa18df = async (db)=>{
|
|
|
257
275
|
}));
|
|
258
276
|
return authors;
|
|
259
277
|
};
|
|
260
|
-
const $
|
|
261
|
-
const rows = await (0, $
|
|
278
|
+
const $09a9521c7a529893$export$7111c27bf38a004f = async (db)=>{
|
|
279
|
+
const rows = await (0, $26460f21c4456828$export$3274d151f0598f1)(db, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Books);
|
|
262
280
|
const books = rows.map((row)=>{
|
|
263
281
|
const r = row;
|
|
264
282
|
return {
|
|
265
|
-
author: $
|
|
283
|
+
author: $09a9521c7a529893$var$parseAuthor(r.author),
|
|
266
284
|
bibliography: r.bibliography,
|
|
267
285
|
category: r.category,
|
|
268
286
|
id: r.id,
|
|
@@ -271,14 +289,14 @@ const $e19722dabbedc0a6$export$7111c27bf38a004f = async (db)=>{
|
|
|
271
289
|
name: r.name,
|
|
272
290
|
printed: r.printed,
|
|
273
291
|
type: r.type,
|
|
274
|
-
...r.date && r.date.toString() !== (0, $
|
|
292
|
+
...r.date && r.date.toString() !== (0, $1857efaf39b32304$export$3deaf0b0365f781e) && {
|
|
275
293
|
date: r.date
|
|
276
294
|
},
|
|
277
295
|
...r.hint && {
|
|
278
296
|
hint: r.hint
|
|
279
297
|
},
|
|
280
298
|
...r.pdf_links && {
|
|
281
|
-
pdfLinks: $
|
|
299
|
+
pdfLinks: $09a9521c7a529893$var$parsePdfLinks(r.pdf_links)
|
|
282
300
|
},
|
|
283
301
|
...r.minor && {
|
|
284
302
|
minorRelease: r.minor
|
|
@@ -287,22 +305,22 @@ const $e19722dabbedc0a6$export$7111c27bf38a004f = async (db)=>{
|
|
|
287
305
|
});
|
|
288
306
|
return books;
|
|
289
307
|
};
|
|
290
|
-
const $
|
|
291
|
-
const rows = await (0, $
|
|
308
|
+
const $09a9521c7a529893$export$36bfd9279b3a24b7 = async (db)=>{
|
|
309
|
+
const rows = await (0, $26460f21c4456828$export$3274d151f0598f1)(db, (0, $e5a23c058b2763fa$export$a17a6870a08b950e).Categories);
|
|
292
310
|
const categories = rows.map((r)=>({
|
|
293
311
|
id: r.id,
|
|
294
312
|
name: r.name
|
|
295
313
|
}));
|
|
296
314
|
return categories;
|
|
297
315
|
};
|
|
298
|
-
const $
|
|
299
|
-
const result = value.split(
|
|
316
|
+
const $09a9521c7a529893$var$parseAuthor = (value)=>{
|
|
317
|
+
const result = value.split(',\\s+').map((id)=>parseInt(id.trim()));
|
|
300
318
|
return result.length > 1 ? result : result[0];
|
|
301
319
|
};
|
|
302
|
-
const $
|
|
320
|
+
const $09a9521c7a529893$var$parsePdfLinks = (value)=>{
|
|
303
321
|
const result = JSON.parse(value);
|
|
304
322
|
if (result.files) result.files = result.files.map((f)=>{
|
|
305
|
-
const [file, id] = f.split(
|
|
323
|
+
const [file, id] = f.split('|');
|
|
306
324
|
return {
|
|
307
325
|
...id && {
|
|
308
326
|
id: id
|
|
@@ -312,11 +330,11 @@ const $e19722dabbedc0a6$var$parsePdfLinks = (value)=>{
|
|
|
312
330
|
});
|
|
313
331
|
return result;
|
|
314
332
|
};
|
|
315
|
-
const $
|
|
333
|
+
const $09a9521c7a529893$export$7a171f172be0782e = async (db)=>{
|
|
316
334
|
const [authors, books, categories] = await Promise.all([
|
|
317
|
-
$
|
|
318
|
-
$
|
|
319
|
-
$
|
|
335
|
+
$09a9521c7a529893$export$b3b931905baa18df(db),
|
|
336
|
+
$09a9521c7a529893$export$7111c27bf38a004f(db),
|
|
337
|
+
$09a9521c7a529893$export$36bfd9279b3a24b7(db)
|
|
320
338
|
]);
|
|
321
339
|
return {
|
|
322
340
|
authors: authors,
|
|
@@ -333,59 +351,59 @@ const $e19722dabbedc0a6$export$7a171f172be0782e = async (db)=>{
|
|
|
333
351
|
|
|
334
352
|
|
|
335
353
|
|
|
336
|
-
const $
|
|
337
|
-
const tempDirBase = (0, $
|
|
338
|
-
return (0, $
|
|
354
|
+
const $fd2c9bc034ddc705$export$1c500f521ad591da = async (prefix = 'shamela')=>{
|
|
355
|
+
const tempDirBase = (0, $SK0tW$path).join((0, $SK0tW$os).tmpdir(), prefix);
|
|
356
|
+
return (0, $SK0tW$promises).mkdtemp(tempDirBase);
|
|
339
357
|
};
|
|
340
|
-
const $
|
|
341
|
-
async function $
|
|
358
|
+
const $fd2c9bc034ddc705$export$ffc21166d570a16 = async (path)=>!!await (0, $SK0tW$promises).stat(path).catch(()=>false);
|
|
359
|
+
async function $fd2c9bc034ddc705$export$fb61e277af91ac0(url, outputDir) {
|
|
342
360
|
const extractedFiles = [];
|
|
343
361
|
const entryPromises = [];
|
|
344
362
|
try {
|
|
345
363
|
// Make HTTPS request and get the response stream
|
|
346
364
|
const response = await new Promise((resolve, reject)=>{
|
|
347
|
-
(0, $
|
|
365
|
+
(0, $SK0tW$https).get(url, (res)=>{
|
|
348
366
|
if (res.statusCode !== 200) reject(new Error(`Failed to download ZIP file: ${res.statusCode} ${res.statusMessage}`));
|
|
349
367
|
else resolve(res);
|
|
350
|
-
}).on(
|
|
368
|
+
}).on('error', (err)=>{
|
|
351
369
|
reject(new Error(`HTTPS request failed: ${err.message}`));
|
|
352
370
|
});
|
|
353
371
|
});
|
|
354
372
|
// Create unzip stream
|
|
355
|
-
const unzipStream = (0, $
|
|
373
|
+
const unzipStream = (0, $SK0tW$unzipper).Parse();
|
|
356
374
|
// Handle entries in the ZIP file
|
|
357
|
-
unzipStream.on(
|
|
375
|
+
unzipStream.on('entry', (entry)=>{
|
|
358
376
|
const entryPromise = (async ()=>{
|
|
359
|
-
const filePath = (0, $
|
|
360
|
-
if (entry.type ===
|
|
377
|
+
const filePath = (0, $SK0tW$path).join(outputDir, entry.path);
|
|
378
|
+
if (entry.type === 'Directory') {
|
|
361
379
|
// Ensure the directory exists
|
|
362
|
-
await (0, $
|
|
380
|
+
await (0, $SK0tW$promises).mkdir(filePath, {
|
|
363
381
|
recursive: true
|
|
364
382
|
});
|
|
365
383
|
entry.autodrain();
|
|
366
384
|
} else {
|
|
367
385
|
// Ensure the parent directory exists
|
|
368
|
-
const dir = (0, $
|
|
369
|
-
await (0, $
|
|
386
|
+
const dir = (0, $SK0tW$path).dirname(filePath);
|
|
387
|
+
await (0, $SK0tW$promises).mkdir(dir, {
|
|
370
388
|
recursive: true
|
|
371
389
|
});
|
|
372
390
|
// Pipe the entry to a file
|
|
373
|
-
await (0, $
|
|
391
|
+
await (0, $SK0tW$pipeline)(entry, (0, $SK0tW$createWriteStream)(filePath));
|
|
374
392
|
extractedFiles.push(filePath);
|
|
375
393
|
}
|
|
376
394
|
})().catch((err)=>{
|
|
377
395
|
// Emit errors to be handled by the unzipStream error handler
|
|
378
|
-
unzipStream.emit(
|
|
396
|
+
unzipStream.emit('error', err);
|
|
379
397
|
});
|
|
380
398
|
// Collect the promises
|
|
381
399
|
entryPromises.push(entryPromise);
|
|
382
400
|
});
|
|
383
401
|
// Handle errors in the unzip stream
|
|
384
|
-
unzipStream.on(
|
|
402
|
+
unzipStream.on('error', (err)=>{
|
|
385
403
|
throw new Error(`Error during extraction: ${err.message}`);
|
|
386
404
|
});
|
|
387
405
|
// Pipe the response into the unzip stream
|
|
388
|
-
await (0, $
|
|
406
|
+
await (0, $SK0tW$pipeline)(response, unzipStream);
|
|
389
407
|
// Wait for all entry promises to complete
|
|
390
408
|
await Promise.all(entryPromises);
|
|
391
409
|
return extractedFiles;
|
|
@@ -400,37 +418,37 @@ async function $e8ee15c0ce3f020d$export$fb61e277af91ac0(url, outputDir) {
|
|
|
400
418
|
|
|
401
419
|
|
|
402
420
|
|
|
403
|
-
const $
|
|
404
|
-
const url = new (0, $
|
|
421
|
+
const $59b98b7fd5edf160$export$b5cd97dee32de81d = (endpoint, params, useAuth = true)=>{
|
|
422
|
+
const url = new (0, $SK0tW$URL)(endpoint);
|
|
405
423
|
{
|
|
406
|
-
const params = new (0, $
|
|
424
|
+
const params = new (0, $SK0tW$URLSearchParams)();
|
|
407
425
|
Object.entries(params).forEach(([key, value])=>{
|
|
408
426
|
params.append(key, value.toString());
|
|
409
427
|
});
|
|
410
|
-
if (useAuth) params.append(
|
|
428
|
+
if (useAuth) params.append('api_key', (0, $SK0tW$process).env.SHAMELA_API_KEY);
|
|
411
429
|
url.search = params.toString();
|
|
412
430
|
}
|
|
413
431
|
return url;
|
|
414
432
|
};
|
|
415
|
-
const $
|
|
433
|
+
const $59b98b7fd5edf160$export$c9e6217566c54f42 = (url)=>{
|
|
416
434
|
return new Promise((resolve, reject)=>{
|
|
417
|
-
(0, $
|
|
418
|
-
const contentType = res.headers[
|
|
435
|
+
(0, $SK0tW$https).get(url, (res)=>{
|
|
436
|
+
const contentType = res.headers['content-type'] || '';
|
|
419
437
|
const dataChunks = [];
|
|
420
|
-
res.on(
|
|
438
|
+
res.on('data', (chunk)=>{
|
|
421
439
|
dataChunks.push(chunk);
|
|
422
440
|
});
|
|
423
|
-
res.on(
|
|
424
|
-
const fullData = (0, $
|
|
425
|
-
if (contentType.includes(
|
|
426
|
-
const json = JSON.parse(fullData.toString(
|
|
441
|
+
res.on('end', ()=>{
|
|
442
|
+
const fullData = (0, $SK0tW$Buffer).concat(dataChunks);
|
|
443
|
+
if (contentType.includes('application/json')) try {
|
|
444
|
+
const json = JSON.parse(fullData.toString('utf-8'));
|
|
427
445
|
resolve(json);
|
|
428
446
|
} catch (error) {
|
|
429
447
|
reject(new Error(`Failed to parse JSON: ${error.message}`));
|
|
430
448
|
}
|
|
431
449
|
else resolve(fullData);
|
|
432
450
|
});
|
|
433
|
-
}).on(
|
|
451
|
+
}).on('error', (error)=>{
|
|
434
452
|
reject(new Error(`Error making request: ${error.message}`));
|
|
435
453
|
});
|
|
436
454
|
});
|
|
@@ -439,34 +457,34 @@ const $932b4b3755196b46$export$c9e6217566c54f42 = (url)=>{
|
|
|
439
457
|
|
|
440
458
|
|
|
441
459
|
|
|
442
|
-
const $
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
460
|
+
const $6605706916cc9c29$var$SOURCE_TABLES = [
|
|
461
|
+
'author.sqlite',
|
|
462
|
+
'book.sqlite',
|
|
463
|
+
'category.sqlite'
|
|
446
464
|
];
|
|
447
|
-
const $
|
|
448
|
-
if (!(0, $
|
|
449
|
-
if (!(0, $
|
|
465
|
+
const $6605706916cc9c29$export$37467b7f8cfc50b0 = ()=>{
|
|
466
|
+
if (!(0, $SK0tW$process).env.SHAMELA_API_MASTER_PATCH_ENDPOINT) throw new Error('SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set');
|
|
467
|
+
if (!(0, $SK0tW$process).env.SHAMELA_API_KEY) throw new Error('SHAMELA_API_KEY environment variable not set');
|
|
450
468
|
};
|
|
451
|
-
const $
|
|
452
|
-
const sourceTableNames = sourceTablePaths.map((tablePath)=>(0, $
|
|
453
|
-
return $
|
|
469
|
+
const $6605706916cc9c29$export$c7660b0cda39b7c3 = (sourceTablePaths)=>{
|
|
470
|
+
const sourceTableNames = sourceTablePaths.map((tablePath)=>(0, $SK0tW$path).parse(tablePath).base);
|
|
471
|
+
return $6605706916cc9c29$var$SOURCE_TABLES.every((table)=>sourceTableNames.includes(table));
|
|
454
472
|
};
|
|
455
473
|
|
|
456
474
|
|
|
457
|
-
const $
|
|
458
|
-
(0, $
|
|
459
|
-
const url = new (0, $
|
|
475
|
+
const $e6ba238abdbefe7a$export$4c209aa17b4b3e57 = async (id, options)=>{
|
|
476
|
+
(0, $6605706916cc9c29$export$37467b7f8cfc50b0)();
|
|
477
|
+
const url = new (0, $SK0tW$URL)(`${(0, $SK0tW$process).env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);
|
|
460
478
|
{
|
|
461
|
-
const params = new (0, $
|
|
462
|
-
params.append(
|
|
463
|
-
params.append(
|
|
464
|
-
params.append(
|
|
479
|
+
const params = new (0, $SK0tW$URLSearchParams)();
|
|
480
|
+
params.append('api_key', (0, $SK0tW$process).env.SHAMELA_API_KEY);
|
|
481
|
+
params.append('major_release', (options?.majorVersion || 0).toString());
|
|
482
|
+
params.append('minor_release', (options?.minorVersion || 0).toString());
|
|
465
483
|
url.search = params.toString();
|
|
466
484
|
}
|
|
467
|
-
(0, $
|
|
485
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Fetching shamela.ws book link: ${url.toString()}`);
|
|
468
486
|
try {
|
|
469
|
-
const response = await (0, $
|
|
487
|
+
const response = await (0, $59b98b7fd5edf160$export$c9e6217566c54f42)(url);
|
|
470
488
|
return {
|
|
471
489
|
majorRelease: response.major_release,
|
|
472
490
|
majorReleaseUrl: response.major_release_url,
|
|
@@ -481,38 +499,38 @@ const $96cb7a03b537cb37$export$4c209aa17b4b3e57 = async (id, options)=>{
|
|
|
481
499
|
throw new Error(`Error fetching master patch: ${error.message}`);
|
|
482
500
|
}
|
|
483
501
|
};
|
|
484
|
-
const $
|
|
485
|
-
(0, $
|
|
486
|
-
const outputDir = await (0, $
|
|
487
|
-
const bookResponse = options?.bookMetadata || await $
|
|
502
|
+
const $e6ba238abdbefe7a$export$3560c45fd9de930d = async (id, options)=>{
|
|
503
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`downloadBook ${id} ${JSON.stringify(options)}`);
|
|
504
|
+
const outputDir = await (0, $fd2c9bc034ddc705$export$1c500f521ad591da)('shamela_downloadBook');
|
|
505
|
+
const bookResponse = options?.bookMetadata || await $e6ba238abdbefe7a$export$4c209aa17b4b3e57(id);
|
|
488
506
|
const [[bookDatabase], [patchDatabase] = []] = await Promise.all([
|
|
489
|
-
(0, $
|
|
507
|
+
(0, $fd2c9bc034ddc705$export$fb61e277af91ac0)(bookResponse.majorReleaseUrl, outputDir),
|
|
490
508
|
...bookResponse.minorReleaseUrl ? [
|
|
491
|
-
(0, $
|
|
509
|
+
(0, $fd2c9bc034ddc705$export$fb61e277af91ac0)(bookResponse.minorReleaseUrl, outputDir)
|
|
492
510
|
] : []
|
|
493
511
|
]);
|
|
494
|
-
const dbPath = (0, $
|
|
495
|
-
const client = (0, $
|
|
512
|
+
const dbPath = (0, $SK0tW$path).join(outputDir, 'book.db');
|
|
513
|
+
const client = (0, $SK0tW$createClient)({
|
|
496
514
|
url: `file:${dbPath}`
|
|
497
515
|
});
|
|
498
516
|
try {
|
|
499
|
-
(0, $
|
|
500
|
-
await (0, $
|
|
517
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Creating tables`);
|
|
518
|
+
await (0, $d7a7877f07ff6c69$export$5d28a6b0dd65e4c4)(client);
|
|
501
519
|
if (patchDatabase) {
|
|
502
|
-
(0, $
|
|
503
|
-
await (0, $
|
|
520
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);
|
|
521
|
+
await (0, $d7a7877f07ff6c69$export$a8b8e03e6bbe5473)(client, bookDatabase, patchDatabase);
|
|
504
522
|
} else {
|
|
505
|
-
(0, $
|
|
506
|
-
await (0, $
|
|
523
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Copying table data from ${bookDatabase}`);
|
|
524
|
+
await (0, $d7a7877f07ff6c69$export$61101aa23c771e7c)(client, bookDatabase);
|
|
507
525
|
}
|
|
508
|
-
const { ext: extension } = (0, $
|
|
509
|
-
if (extension ===
|
|
510
|
-
const result = await (0, $
|
|
511
|
-
await (0, $
|
|
526
|
+
const { ext: extension } = (0, $SK0tW$path).parse(options.outputFile.path);
|
|
527
|
+
if (extension === '.json') {
|
|
528
|
+
const result = await (0, $d7a7877f07ff6c69$export$7a171f172be0782e)(client);
|
|
529
|
+
await (0, $SK0tW$promises).writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');
|
|
512
530
|
}
|
|
513
531
|
client.close();
|
|
514
|
-
if (extension ===
|
|
515
|
-
await (0, $
|
|
532
|
+
if (extension === '.db' || extension === '.sqlite') await (0, $SK0tW$promises).rename(dbPath, options.outputFile.path);
|
|
533
|
+
await (0, $SK0tW$promises).rm(outputDir, {
|
|
516
534
|
recursive: true
|
|
517
535
|
});
|
|
518
536
|
} finally{
|
|
@@ -520,18 +538,18 @@ const $96cb7a03b537cb37$export$3560c45fd9de930d = async (id, options)=>{
|
|
|
520
538
|
}
|
|
521
539
|
return options.outputFile.path;
|
|
522
540
|
};
|
|
523
|
-
const $
|
|
524
|
-
(0, $
|
|
525
|
-
const url = new (0, $
|
|
541
|
+
const $e6ba238abdbefe7a$export$b96de494209cdc35 = async (version = 0)=>{
|
|
542
|
+
(0, $6605706916cc9c29$export$37467b7f8cfc50b0)();
|
|
543
|
+
const url = new (0, $SK0tW$URL)((0, $SK0tW$process).env.SHAMELA_API_MASTER_PATCH_ENDPOINT);
|
|
526
544
|
{
|
|
527
|
-
const params = new (0, $
|
|
528
|
-
params.append(
|
|
529
|
-
params.append(
|
|
545
|
+
const params = new (0, $SK0tW$URLSearchParams)();
|
|
546
|
+
params.append('api_key', (0, $SK0tW$process).env.SHAMELA_API_KEY);
|
|
547
|
+
params.append('version', version.toString());
|
|
530
548
|
url.search = params.toString();
|
|
531
549
|
}
|
|
532
|
-
(0, $
|
|
550
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Fetching shamela.ws master database patch link: ${url.toString()}`);
|
|
533
551
|
try {
|
|
534
|
-
const response = await (0, $
|
|
552
|
+
const response = await (0, $59b98b7fd5edf160$export$c9e6217566c54f42)(url);
|
|
535
553
|
return {
|
|
536
554
|
url: response.patch_url,
|
|
537
555
|
version: response.version
|
|
@@ -540,34 +558,34 @@ const $96cb7a03b537cb37$export$b96de494209cdc35 = async (version = 0)=>{
|
|
|
540
558
|
throw new Error(`Error fetching master patch: ${error.message}`);
|
|
541
559
|
}
|
|
542
560
|
};
|
|
543
|
-
const $
|
|
544
|
-
(0, $
|
|
545
|
-
const outputDir = await (0, $
|
|
546
|
-
const masterResponse = options.masterMetadata || await $
|
|
547
|
-
(0, $
|
|
548
|
-
const sourceTables = await (0, $
|
|
549
|
-
(0, $
|
|
550
|
-
if (!(0, $
|
|
551
|
-
(0, $
|
|
552
|
-
throw new Error(
|
|
561
|
+
const $e6ba238abdbefe7a$export$fd8b6353fde3f1de = async (options)=>{
|
|
562
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`downloadMasterDatabase ${JSON.stringify(options)}`);
|
|
563
|
+
const outputDir = await (0, $fd2c9bc034ddc705$export$1c500f521ad591da)('shamela_downloadMaster');
|
|
564
|
+
const masterResponse = options.masterMetadata || await $e6ba238abdbefe7a$export$b96de494209cdc35((0, $1857efaf39b32304$export$5bc725975f47e62c));
|
|
565
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);
|
|
566
|
+
const sourceTables = await (0, $fd2c9bc034ddc705$export$fb61e277af91ac0)(masterResponse.url, outputDir);
|
|
567
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`sourceTables downloaded: ${sourceTables.toString()}`);
|
|
568
|
+
if (!(0, $6605706916cc9c29$export$c7660b0cda39b7c3)(sourceTables)) {
|
|
569
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).error(`Some source tables were not found: ${sourceTables.toString()}`);
|
|
570
|
+
throw new Error('Expected tables not found!');
|
|
553
571
|
}
|
|
554
|
-
const dbPath = (0, $
|
|
555
|
-
const client = (0, $
|
|
572
|
+
const dbPath = (0, $SK0tW$path).join(outputDir, 'master.db');
|
|
573
|
+
const client = (0, $SK0tW$createClient)({
|
|
556
574
|
url: `file:${dbPath}`
|
|
557
575
|
});
|
|
558
576
|
try {
|
|
559
|
-
(0, $
|
|
560
|
-
await (0, $
|
|
561
|
-
(0, $
|
|
562
|
-
await (0, $
|
|
563
|
-
const { ext: extension } = (0, $
|
|
564
|
-
if (extension ===
|
|
565
|
-
const result = await (0, $
|
|
566
|
-
await (0, $
|
|
577
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Creating tables`);
|
|
578
|
+
await (0, $09a9521c7a529893$export$5d28a6b0dd65e4c4)(client);
|
|
579
|
+
(0, $526b48a37e8a8ec6$export$2e2bcd8739ae039).info(`Copying data to master table`);
|
|
580
|
+
await (0, $09a9521c7a529893$export$b3179f41dfd6e35b)(client, sourceTables);
|
|
581
|
+
const { ext: extension } = (0, $SK0tW$path).parse(options.outputFile.path);
|
|
582
|
+
if (extension === '.json') {
|
|
583
|
+
const result = await (0, $09a9521c7a529893$export$7a171f172be0782e)(client);
|
|
584
|
+
await (0, $SK0tW$promises).writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');
|
|
567
585
|
}
|
|
568
586
|
client.close();
|
|
569
|
-
if (extension ===
|
|
570
|
-
await (0, $
|
|
587
|
+
if (extension === '.db' || extension === '.sqlite') await (0, $SK0tW$promises).rename(dbPath, options.outputFile.path);
|
|
588
|
+
await (0, $SK0tW$promises).rm(outputDir, {
|
|
571
589
|
recursive: true
|
|
572
590
|
});
|
|
573
591
|
} finally{
|
|
@@ -575,25 +593,25 @@ const $96cb7a03b537cb37$export$fd8b6353fde3f1de = async (options)=>{
|
|
|
575
593
|
}
|
|
576
594
|
return options.outputFile.path;
|
|
577
595
|
};
|
|
578
|
-
const $
|
|
579
|
-
const outputDir = await (0, $
|
|
580
|
-
const outputPath = await $
|
|
596
|
+
const $e6ba238abdbefe7a$export$be7c2acc48adceee = async (id)=>{
|
|
597
|
+
const outputDir = await (0, $fd2c9bc034ddc705$export$1c500f521ad591da)('shamela_getBookData');
|
|
598
|
+
const outputPath = await $e6ba238abdbefe7a$export$3560c45fd9de930d(id, {
|
|
581
599
|
outputFile: {
|
|
582
|
-
path: (0, $
|
|
600
|
+
path: (0, $SK0tW$path).join(outputDir, `${id}.json`)
|
|
583
601
|
}
|
|
584
602
|
});
|
|
585
|
-
const data = JSON.parse(await (0, $
|
|
586
|
-
await (0, $
|
|
603
|
+
const data = JSON.parse(await (0, $SK0tW$promises).readFile(outputPath, 'utf8'));
|
|
604
|
+
await (0, $SK0tW$promises).rm(outputDir, {
|
|
587
605
|
recursive: true
|
|
588
606
|
});
|
|
589
607
|
return data;
|
|
590
608
|
};
|
|
591
609
|
|
|
592
610
|
|
|
593
|
-
var $
|
|
611
|
+
var $e9528ebec83086b6$exports = {};
|
|
594
612
|
|
|
595
613
|
|
|
596
614
|
|
|
597
615
|
|
|
598
|
-
export {$
|
|
616
|
+
export {$e6ba238abdbefe7a$export$3560c45fd9de930d as downloadBook, $e6ba238abdbefe7a$export$fd8b6353fde3f1de as downloadMasterDatabase, $e6ba238abdbefe7a$export$be7c2acc48adceee as getBook, $e6ba238abdbefe7a$export$4c209aa17b4b3e57 as getBookMetadata, $e6ba238abdbefe7a$export$b96de494209cdc35 as getMasterMetadata};
|
|
599
617
|
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["src/index.ts","src/api.ts","src/db/book.ts","src/utils/logger.ts","src/db/common.ts","src/db/queryBuilder.ts","src/db/types.ts","src/db/master.ts","src/utils/constants.ts","src/utils/io.ts","src/utils/network.ts","src/utils/validation.ts","src/types.ts"],"sourcesContent":["import { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata } from './api';\n\nexport { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata };\n\nexport * from './types';\n","import { Client, createClient } from '@libsql/client';\nimport { promises as fs } from 'fs';\nimport path from 'path';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nimport { applyPatches, copyTableData, createTables as createBookTables, getData as getBookData } from './db/book.js';\nimport {\n copyForeignMasterTableData,\n createTables as createMasterTables,\n getData as getMasterData,\n} from './db/master.js';\nimport {\n BookData,\n DownloadBookOptions,\n DownloadMasterOptions,\n GetBookMetadataOptions,\n GetBookMetadataResponsePayload,\n GetMasterMetadataResponsePayload,\n} from './types.js';\nimport { DEFAULT_MASTER_METADATA_VERSION } from './utils/constants.js';\nimport { createTempDir, unzipFromUrl } from './utils/io.js';\nimport logger from './utils/logger.js';\nimport { httpsGet } from './utils/network.js';\nimport { validateEnvVariables, validateMasterSourceTables } from './utils/validation.js';\n\nexport const getBookMetadata = async (\n id: number,\n options?: GetBookMetadataOptions,\n): Promise<GetBookMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(`${process.env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('major_release', (options?.majorVersion || 0).toString());\n params.append('minor_release', (options?.minorVersion || 0).toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws book link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return {\n majorRelease: response.major_release,\n majorReleaseUrl: response.major_release_url,\n ...(response.minor_release_url && { minorReleaseUrl: response.minor_release_url }),\n ...(response.minor_release_url && { minorRelease: response.minor_release }),\n };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadBook = async (id: number, options: DownloadBookOptions): Promise<string> => {\n logger.info(`downloadBook ${id} ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadBook');\n\n const bookResponse: GetBookMetadataResponsePayload = options?.bookMetadata || (await getBookMetadata(id));\n const [[bookDatabase], [patchDatabase] = []]: string[][] = await Promise.all([\n unzipFromUrl(bookResponse.majorReleaseUrl, outputDir),\n ...(bookResponse.minorReleaseUrl ? [unzipFromUrl(bookResponse.minorReleaseUrl, outputDir)] : []),\n ]);\n const dbPath = path.join(outputDir, 'book.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createBookTables(client);\n\n if (patchDatabase) {\n logger.info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);\n await applyPatches(client, bookDatabase, patchDatabase);\n } else {\n logger.info(`Copying table data from ${bookDatabase}`);\n await copyTableData(client, bookDatabase);\n }\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getBookData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getMasterMetadata = async (version: number = 0): Promise<GetMasterMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT as string);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('version', version.toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws master database patch link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return { url: response.patch_url, version: response.version };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadMasterDatabase = async (options: DownloadMasterOptions): Promise<string> => {\n logger.info(`downloadMasterDatabase ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadMaster');\n\n const masterResponse: GetMasterMetadataResponsePayload =\n options.masterMetadata || (await getMasterMetadata(DEFAULT_MASTER_METADATA_VERSION));\n\n logger.info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);\n const sourceTables: string[] = await unzipFromUrl(masterResponse.url, outputDir);\n\n logger.info(`sourceTables downloaded: ${sourceTables.toString()}`);\n\n if (!validateMasterSourceTables(sourceTables)) {\n logger.error(`Some source tables were not found: ${sourceTables.toString()}`);\n throw new Error('Expected tables not found!');\n }\n\n const dbPath = path.join(outputDir, 'master.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createMasterTables(client);\n\n logger.info(`Copying data to master table`);\n await copyForeignMasterTableData(client, sourceTables);\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getMasterData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getBook = async (id: number): Promise<BookData> => {\n const outputDir = await createTempDir('shamela_getBookData');\n const outputPath = await downloadBook(id, { outputFile: { path: path.join(outputDir, `${id}.json`) } });\n\n const data = JSON.parse(await fs.readFile(outputPath, 'utf8')) as BookData;\n await fs.rm(outputDir, { recursive: true });\n\n return data;\n};\n","import { Client } from '@libsql/client';\n\nimport { BookData, Page, Title } from '../types';\nimport logger from '../utils/logger';\nimport { getInternalTables, InternalTable, selectAllRows } from './common';\nimport { attachDB, buildPagePatchQuery, buildTitlePatchQuery, detachDB } from './queryBuilder';\nimport { PageRow, Tables, TitleRow } from './types';\n\nconst PATCH_DB_ALIAS = 'patch';\nconst ASL_DB_ALIAS = 'asl';\n\nconst getPagesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Page)) {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0')`,\n );\n statements.push(buildPagePatchQuery(PATCH_DB_ALIAS, Tables.Page));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nconst getTitlesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Title)) {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0')`,\n );\n statements.push(buildTitlePatchQuery(PATCH_DB_ALIAS, Tables.Title));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nexport const applyPatches = async (db: Client, aslDB: string, patchDB?: string) => {\n const statements: string[] = [attachDB(aslDB, ASL_DB_ALIAS)];\n\n if (patchDB) {\n await db.execute(attachDB(patchDB, PATCH_DB_ALIAS));\n }\n\n const tables = patchDB ? await getInternalTables(db, PATCH_DB_ALIAS) : [];\n\n logger.debug({ tables }, `Applying patches for...`);\n\n statements.push(...getPagesToCopy(tables));\n statements.push(...getTitlesToCopy(tables));\n\n await db.batch(statements);\n\n const detachStatements = [];\n detachStatements.push(detachDB(ASL_DB_ALIAS));\n\n if (patchDB) {\n detachStatements.push(detachDB(PATCH_DB_ALIAS));\n }\n\n return db.batch(detachStatements);\n};\n\nexport const copyTableData = async (db: Client, aslDB: string) => {\n await db.execute(attachDB(aslDB, ASL_DB_ALIAS));\n const tables = await getInternalTables(db, ASL_DB_ALIAS);\n\n logger.debug({ tables }, `Applying patches for...`);\n\n await db.batch([\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title}`,\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page}`,\n ]);\n\n return db.execute(detachDB(ASL_DB_ALIAS));\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,\n `CREATE TABLE title (id INTEGER PRIMARY KEY, content TEXT, page INTEGER, parent INTEGER)`,\n ]);\n};\n\nexport const getAllPages = async (db: Client): Promise<Page[]> => {\n const rows = await selectAllRows(db, Tables.Page);\n\n const pages: Page[] = rows.map((row: any) => {\n const { content, id, number, page, part } = row as PageRow;\n\n return {\n content,\n id,\n ...(page && { page }),\n ...(number && { number }),\n ...(part && { part }),\n };\n });\n\n return pages;\n};\n\nexport const getAllTitles = async (db: Client): Promise<Title[]> => {\n const rows = await selectAllRows(db, Tables.Title);\n\n const titles: Title[] = rows.map((row: any) => {\n const r = row as TitleRow;\n\n return {\n content: r.content,\n id: r.id,\n page: r.page,\n ...(r.parent && { number: r.parent }),\n };\n });\n\n return titles;\n};\n\nexport const getData = async (db: Client): Promise<BookData> => {\n const [pages, titles] = await Promise.all([getAllPages(db), getAllTitles(db)]);\n return { pages, titles };\n};\n","import pino, { Logger } from 'pino';\nimport pretty, { PrettyOptions } from 'pino-pretty';\nimport process from 'process';\n\nconst stream = pretty({\n colorize: true,\n} as PrettyOptions);\n\nconst logger: Logger = pino(\n {\n base: { pid: undefined, hostname: undefined }, // This will remove pid and hostname but keep time\n level: process.env.LOG_LEVEL || 'info',\n },\n stream,\n);\n\nexport default logger;\n","import { Client, Row } from '@libsql/client';\n\nexport type InternalTable = {\n name: string;\n};\n\nexport const getInternalTables = async (db: Client, dbName: string): Promise<InternalTable[]> => {\n const { rows: tables } = await db.execute(`SELECT name FROM ${dbName}.sqlite_master WHERE type='table'`);\n\n return tables as unknown as InternalTable[];\n};\n\nexport const selectAllRows = async (client: Client, table: string): Promise<Row[]> => {\n const { rows } = await client.execute(`SELECT * FROM ${table}`);\n return rows;\n};\n","const MAIN_DB_ALIAS = 'main';\n\nexport const attachDB = (dbFile: string, alias: string) => `ATTACH DATABASE '${dbFile}' AS ${alias}`;\n\nexport const buildPagePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updatePageColumn('content', aslAlias, patchAlias)},\n part = ${updatePageColumn('part', aslAlias, patchAlias)},\n page = ${updatePageColumn('page', aslAlias, patchAlias)},\n number = ${updatePageColumn('number', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nconst updateTitleColumn = (columnName: string, aslAlias: string, patchAlias: string) => `\n (SELECT CASE \n WHEN ${patchAlias}.title.${columnName} != '#' THEN ${patchAlias}.title.${columnName}\n ELSE ${aslAlias}.title.${columnName}\n END \n FROM ${patchAlias}.title\n WHERE ${aslAlias}.title.id = ${patchAlias}.title.id)\n`;\n\nexport const buildTitlePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updateTitleColumn('content', aslAlias, patchAlias)},\n page = ${updateTitleColumn('page', aslAlias, patchAlias)},\n parent = ${updateTitleColumn('parent', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nexport const createTable = (name: string, fields: string[]): string =>\n `CREATE TABLE IF NOT EXISTS ${name} (${fields.join(', ')})`;\n\nexport const detachDB = (alias: string) => `DETACH DATABASE ${alias}`;\n\nconst updatePageColumn = (columnName: string, aslAlias: string, patchAlias: string): string => `\n (SELECT CASE \n WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}\n ELSE ${aslAlias}.page.${columnName}\n END \n FROM ${patchAlias}.page\n WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)\n`;\n\nexport const insertUnsafely = (table: string, fieldToValue: Record<string, any>, isDeleted = false): string => {\n const combinedRecords: Record<string, any> = { ...fieldToValue, is_deleted: isDeleted ? '1' : '0' };\n\n const sortedKeys = Object.keys(combinedRecords).sort();\n\n const sortedValues = sortedKeys.map((key) => combinedRecords[key]);\n\n return `INSERT INTO ${table} (${sortedKeys.toString()}) VALUES (${sortedValues\n .map((val) => {\n if (val === null) {\n return 'NULL';\n }\n\n return typeof val === 'string' ? `'${val}'` : val;\n })\n .toString()})`;\n};\n","export type AuthorRow = {\n biography: string;\n death: number;\n id: number;\n name: string;\n};\n\nexport type BookRow = {\n author: string;\n bibliography: string;\n category: number;\n date?: null | number;\n hint: null | string;\n id: number;\n major: number;\n metadata: string;\n minor?: number;\n name: string;\n pdf_links: null | string;\n printed: number;\n type: number;\n};\n\nexport type PageRow = {\n content: string;\n id: number;\n number: null | number;\n page: null | number;\n part: null | number;\n};\n\nexport type TitleRow = {\n content: string;\n id: number;\n page: number;\n parent: null | number;\n};\n\nexport type CategoryRow = {\n id: number;\n name: string;\n};\n\nexport enum Tables {\n Authors = 'authors',\n Books = 'books',\n Categories = 'categories',\n Page = 'page',\n Title = 'title',\n}\n","import { Client } from '@libsql/client';\nimport path from 'path';\n\nimport { Author, Book, Category, MasterData, PDFLinks } from '../types';\nimport { UNKNOWN_VALUE_PLACEHOLDER } from '../utils/constants';\nimport { selectAllRows } from './common';\nimport { attachDB, detachDB } from './queryBuilder';\nimport { BookRow, Tables } from './types';\n\nexport const copyForeignMasterTableData = async (db: Client, sourceTables: string[]) => {\n const aliasToPath: Record<string, string> = sourceTables.reduce((acc, tablePath) => {\n const { name } = path.parse(tablePath);\n return { ...acc, [name]: tablePath };\n }, {});\n\n const attachStatements: string[] = Object.entries(aliasToPath).map(([alias, dbPath]) => attachDB(dbPath, alias));\n await db.batch(attachStatements);\n\n const insertStatements: string[] = [\n `INSERT INTO ${Tables.Authors} SELECT id,name,biography,(CASE WHEN death_number = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Books} SELECT id,name,category,type,(CASE WHEN date = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Categories} SELECT id,name FROM category WHERE is_deleted='0'`,\n ];\n await db.batch(insertStatements);\n\n const detachStatements: string[] = Object.keys(aliasToPath).map(detachDB);\n await db.batch(detachStatements);\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,\n `CREATE TABLE books (id INTEGER PRIMARY KEY, name TEXT, category INTEGER, type INTEGER, date INTEGER, author TEXT, printed INTEGER, major INTEGER, minor INTEGER, bibliography TEXT, hint TEXT, pdf_links TEXT, metadata TEXT)`,\n `CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)`,\n ]);\n};\n\nexport const getAllAuthors = async (db: Client): Promise<Author[]> => {\n const rows = await selectAllRows(db, Tables.Authors);\n\n const authors: Author[] = rows.map((r: any) => ({\n ...(r.biography && { biography: r.biography }),\n ...(r.death && { death: r.death }),\n id: r.id,\n name: r.name,\n }));\n\n return authors;\n};\n\nexport const getAllBooks = async (db: Client): Promise<Book[]> => {\n const rows = await selectAllRows(db, Tables.Books);\n\n const books: Book[] = rows.map((row: any) => {\n const r = row as BookRow;\n\n return {\n author: parseAuthor(r.author),\n bibliography: r.bibliography,\n category: r.category,\n id: r.id,\n major: r.major,\n metadata: JSON.parse(r.metadata),\n name: r.name,\n printed: r.printed,\n type: r.type,\n ...(r.date && r.date.toString() !== UNKNOWN_VALUE_PLACEHOLDER && { date: r.date }),\n ...(r.hint && { hint: r.hint }),\n ...(r.pdf_links && { pdfLinks: parsePdfLinks(r.pdf_links) }),\n ...(r.minor && { minorRelease: r.minor }),\n };\n });\n\n return books;\n};\n\nexport const getAllCategories = async (db: Client): Promise<Category[]> => {\n const rows = await selectAllRows(db, Tables.Categories);\n\n const categories: Category[] = rows.map((r: any) => ({\n id: r.id,\n name: r.name,\n }));\n\n return categories;\n};\n\nconst parseAuthor = (value: string): number | number[] => {\n const result: number[] = value.split(',\\\\s+').map((id) => parseInt(id.trim()));\n return result.length > 1 ? result : result[0];\n};\n\nconst parsePdfLinks = (value: string): PDFLinks => {\n const result = JSON.parse(value);\n\n if (result.files) {\n result.files = (result.files as string[]).map((f: string) => {\n const [file, id] = f.split('|');\n return { ...(id && { id }), file };\n });\n }\n\n return result as PDFLinks;\n};\n\nexport const getData = async (db: Client): Promise<MasterData> => {\n const [authors, books, categories] = await Promise.all([getAllAuthors(db), getAllBooks(db), getAllCategories(db)]);\n return { authors, books, categories };\n};\n","export const DEFAULT_MASTER_METADATA_VERSION = 0;\n\nexport const UNKNOWN_VALUE_PLACEHOLDER = '99999';\n","import { createWriteStream, promises as fs } from 'fs';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport os from 'os';\nimport path from 'path';\nimport { pipeline } from 'stream/promises';\nimport unzipper, { Entry } from 'unzipper';\n\nexport const createTempDir = async (prefix = 'shamela') => {\n const tempDirBase = path.join(os.tmpdir(), prefix);\n return fs.mkdtemp(tempDirBase);\n};\n\nexport const fileExists = async (path: string) => !!(await fs.stat(path).catch(() => false));\n\n/**\n * Downloads and extracts a ZIP file from a given URL without loading the entire file into memory.\n *\n * @param url - The URL of the ZIP file to download and extract.\n * @param outputDir - The directory where the files should be extracted.\n * @returns A promise that resolves with the list of all extracted files.\n */\nexport async function unzipFromUrl(url: string, outputDir: string): Promise<string[]> {\n const extractedFiles: string[] = [];\n const entryPromises: Promise<void>[] = [];\n\n try {\n // Make HTTPS request and get the response stream\n const response = await new Promise<IncomingMessage>((resolve, reject) => {\n https\n .get(url, (res) => {\n if (res.statusCode !== 200) {\n reject(new Error(`Failed to download ZIP file: ${res.statusCode} ${res.statusMessage}`));\n } else {\n resolve(res);\n }\n })\n .on('error', (err) => {\n reject(new Error(`HTTPS request failed: ${err.message}`));\n });\n });\n\n // Create unzip stream\n const unzipStream = unzipper.Parse();\n\n // Handle entries in the ZIP file\n unzipStream.on('entry', (entry: Entry) => {\n const entryPromise = (async () => {\n const filePath = path.join(outputDir, entry.path);\n\n if (entry.type === 'Directory') {\n // Ensure the directory exists\n await fs.mkdir(filePath, { recursive: true });\n entry.autodrain();\n } else {\n // Ensure the parent directory exists\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n\n // Pipe the entry to a file\n await pipeline(entry, createWriteStream(filePath));\n extractedFiles.push(filePath);\n }\n })().catch((err) => {\n // Emit errors to be handled by the unzipStream error handler\n unzipStream.emit('error', err);\n });\n\n // Collect the promises\n entryPromises.push(entryPromise);\n });\n\n // Handle errors in the unzip stream\n unzipStream.on('error', (err) => {\n throw new Error(`Error during extraction: ${err.message}`);\n });\n\n // Pipe the response into the unzip stream\n await pipeline(response, unzipStream);\n\n // Wait for all entry promises to complete\n await Promise.all(entryPromises);\n\n return extractedFiles;\n } catch (error: any) {\n throw new Error(`Error processing URL: ${error.message}`);\n }\n}\n","import { Buffer } from 'buffer';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nexport const buildUrl = (endpoint: string, params: Record<string, any>, useAuth: boolean = true): URL => {\n const url = new URL(endpoint);\n {\n const params = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n params.append(key, value.toString());\n });\n\n if (useAuth) {\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n }\n\n url.search = params.toString();\n }\n\n return url;\n};\n\nexport const httpsGet = (url: string | URL): Promise<Buffer | Record<string, any>> => {\n return new Promise((resolve, reject) => {\n https\n .get(url, (res: IncomingMessage) => {\n const contentType = res.headers['content-type'] || '';\n const dataChunks: Buffer[] = [];\n\n res.on('data', (chunk: Buffer) => {\n dataChunks.push(chunk);\n });\n\n res.on('end', () => {\n const fullData = Buffer.concat(dataChunks);\n\n if (contentType.includes('application/json')) {\n try {\n const json = JSON.parse(fullData.toString('utf-8'));\n resolve(json);\n } catch (error: any) {\n reject(new Error(`Failed to parse JSON: ${error.message}`));\n }\n } else {\n resolve(fullData);\n }\n });\n })\n .on('error', (error) => {\n reject(new Error(`Error making request: ${error.message}`));\n });\n });\n};\n","import path from 'path';\nimport process from 'process';\n\nconst SOURCE_TABLES = ['author.sqlite', 'book.sqlite', 'category.sqlite'];\n\nexport const validateEnvVariables = () => {\n if (!process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT) {\n throw new Error('SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set');\n }\n\n if (!process.env.SHAMELA_API_KEY) {\n throw new Error('SHAMELA_API_KEY environment variable not set');\n }\n};\n\nexport const validateMasterSourceTables = (sourceTablePaths: string[]) => {\n const sourceTableNames = sourceTablePaths.map((tablePath) => path.parse(tablePath).base);\n return SOURCE_TABLES.every((table) => sourceTableNames.includes(table));\n};\n","export type GetMasterMetadataResponsePayload = {\n url: string;\n version: number;\n};\n\nexport interface OutputOptions {\n path: string;\n}\n\nexport type DownloadMasterOptions = {\n masterMetadata?: GetMasterMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type GetBookMetadataOptions = {\n majorVersion: number;\n minorVersion: number;\n};\n\nexport type GetBookMetadataResponsePayload = {\n majorRelease: number;\n majorReleaseUrl: string;\n minorRelease?: number;\n minorReleaseUrl?: string;\n};\n\nexport type DownloadBookOptions = {\n bookMetadata?: GetBookMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type Author = {\n biography?: string;\n death?: number;\n id: number;\n name: string;\n};\n\ntype PDFFile = {\n file: string;\n id?: string;\n};\n\nexport type PDFLinks = {\n alias?: number;\n cover?: number;\n cover_alias?: number;\n files?: PDFFile[];\n root?: string;\n size?: number;\n};\n\nexport type Metadata = {\n coauthor?: number[];\n date: string;\n group?: number;\n hide_diacritic?: boolean;\n min_ver?: number;\n prefix?: string;\n shorts: Record<string, string>;\n sub_books: number[];\n suffix?: string;\n};\n\nexport type Book = {\n author: number | number[];\n bibliography: string;\n category: number;\n date?: number;\n hint?: string;\n id: number;\n major: number;\n metadata: Metadata;\n minor?: number;\n name: string;\n pdfLinks?: PDFLinks;\n printed: number;\n type: number;\n};\n\nexport type Category = {\n id: number;\n name: string;\n};\n\nexport type MasterData = {\n authors: Author[];\n books: Book[];\n categories: Category[];\n};\n\nexport type Page = {\n content: string;\n id: number;\n number?: number;\n page?: number;\n part?: number;\n};\n\nexport type Title = {\n content: string;\n id: number;\n page: number;\n parent?: number;\n};\n\nexport type BookData = {\n pages: Page[];\n titles?: Title[];\n};\n"],"names":[],"version":3,"file":"main.js.map","sourceRoot":"../"}
|
|
1
|
+
{"mappings":"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","sources":["src/index.ts","src/api.ts","src/db/book.ts","src/utils/logger.ts","src/db/common.ts","src/db/queryBuilder.ts","src/db/types.ts","src/db/master.ts","src/utils/constants.ts","src/utils/io.ts","src/utils/network.ts","src/utils/validation.ts","src/types.ts"],"sourcesContent":["import { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata } from './api';\n\nexport { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata };\n\nexport * from './types';\n","import { Client, createClient } from '@libsql/client';\nimport { promises as fs } from 'fs';\nimport path from 'path';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nimport { applyPatches, copyTableData, createTables as createBookTables, getData as getBookData } from './db/book.js';\nimport {\n copyForeignMasterTableData,\n createTables as createMasterTables,\n getData as getMasterData,\n} from './db/master.js';\nimport {\n BookData,\n DownloadBookOptions,\n DownloadMasterOptions,\n GetBookMetadataOptions,\n GetBookMetadataResponsePayload,\n GetMasterMetadataResponsePayload,\n} from './types.js';\nimport { DEFAULT_MASTER_METADATA_VERSION } from './utils/constants.js';\nimport { createTempDir, unzipFromUrl } from './utils/io.js';\nimport logger from './utils/logger.js';\nimport { httpsGet } from './utils/network.js';\nimport { validateEnvVariables, validateMasterSourceTables } from './utils/validation.js';\n\nexport const getBookMetadata = async (\n id: number,\n options?: GetBookMetadataOptions,\n): Promise<GetBookMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(`${process.env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('major_release', (options?.majorVersion || 0).toString());\n params.append('minor_release', (options?.minorVersion || 0).toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws book link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return {\n majorRelease: response.major_release,\n majorReleaseUrl: response.major_release_url,\n ...(response.minor_release_url && { minorReleaseUrl: response.minor_release_url }),\n ...(response.minor_release_url && { minorRelease: response.minor_release }),\n };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadBook = async (id: number, options: DownloadBookOptions): Promise<string> => {\n logger.info(`downloadBook ${id} ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadBook');\n\n const bookResponse: GetBookMetadataResponsePayload = options?.bookMetadata || (await getBookMetadata(id));\n const [[bookDatabase], [patchDatabase] = []]: string[][] = await Promise.all([\n unzipFromUrl(bookResponse.majorReleaseUrl, outputDir),\n ...(bookResponse.minorReleaseUrl ? [unzipFromUrl(bookResponse.minorReleaseUrl, outputDir)] : []),\n ]);\n const dbPath = path.join(outputDir, 'book.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createBookTables(client);\n\n if (patchDatabase) {\n logger.info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);\n await applyPatches(client, bookDatabase, patchDatabase);\n } else {\n logger.info(`Copying table data from ${bookDatabase}`);\n await copyTableData(client, bookDatabase);\n }\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getBookData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getMasterMetadata = async (version: number = 0): Promise<GetMasterMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT as string);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('version', version.toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws master database patch link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return { url: response.patch_url, version: response.version };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadMasterDatabase = async (options: DownloadMasterOptions): Promise<string> => {\n logger.info(`downloadMasterDatabase ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadMaster');\n\n const masterResponse: GetMasterMetadataResponsePayload =\n options.masterMetadata || (await getMasterMetadata(DEFAULT_MASTER_METADATA_VERSION));\n\n logger.info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);\n const sourceTables: string[] = await unzipFromUrl(masterResponse.url, outputDir);\n\n logger.info(`sourceTables downloaded: ${sourceTables.toString()}`);\n\n if (!validateMasterSourceTables(sourceTables)) {\n logger.error(`Some source tables were not found: ${sourceTables.toString()}`);\n throw new Error('Expected tables not found!');\n }\n\n const dbPath = path.join(outputDir, 'master.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createMasterTables(client);\n\n logger.info(`Copying data to master table`);\n await copyForeignMasterTableData(client, sourceTables);\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getMasterData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getBook = async (id: number): Promise<BookData> => {\n const outputDir = await createTempDir('shamela_getBookData');\n const outputPath = await downloadBook(id, { outputFile: { path: path.join(outputDir, `${id}.json`) } });\n\n const data = JSON.parse(await fs.readFile(outputPath, 'utf8')) as BookData;\n await fs.rm(outputDir, { recursive: true });\n\n return data;\n};\n","import { Client } from '@libsql/client';\n\nimport { BookData, Page, Title } from '../types';\nimport logger from '../utils/logger';\nimport { getInternalTables, InternalTable, selectAllRows } from './common';\nimport { attachDB, buildPagePatchQuery, buildTitlePatchQuery, detachDB } from './queryBuilder';\nimport { PageRow, Tables, TitleRow } from './types';\n\nconst PATCH_DB_ALIAS = 'patch';\nconst ASL_DB_ALIAS = 'asl';\n\nconst buildCopyStatements = (\n patchTables: InternalTable[],\n aslTables: InternalTable[],\n table: Tables,\n fields: string[],\n patchQuery: string,\n): string[] => {\n const statements = [];\n\n if (patchTables.find((t) => t.name === table)) {\n statements.push(\n `INSERT INTO main.${table} SELECT ${fields.join(',')} FROM ${ASL_DB_ALIAS}.${table} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${table} WHERE is_deleted='0')`,\n );\n statements.push(patchQuery);\n } else {\n let copyStatement = `INSERT INTO main.${table} SELECT ${fields.join(',')} FROM ${ASL_DB_ALIAS}.${table}`;\n\n if (aslTables.find((t) => t.name === table)?.fields.includes('is_deleted')) {\n copyStatement += ` WHERE is_deleted='0'`;\n }\n\n statements.push(copyStatement);\n }\n\n return statements;\n};\n\nexport const applyPatches = async (db: Client, aslDB: string, patchDB: string) => {\n await Promise.all([db.execute(attachDB(aslDB, ASL_DB_ALIAS)), db.execute(attachDB(patchDB, PATCH_DB_ALIAS))]);\n\n const [patchTables, aslTables] = await Promise.all([\n getInternalTables(db, PATCH_DB_ALIAS),\n getInternalTables(db, ASL_DB_ALIAS),\n ]);\n\n logger.debug({ aslTables, patchTables }, `Applying patches for...`);\n\n await db.batch([\n ...buildCopyStatements(\n patchTables,\n aslTables,\n Tables.Page,\n ['id', 'content', 'part', 'page', 'number'],\n buildPagePatchQuery(PATCH_DB_ALIAS, Tables.Page),\n ),\n ...buildCopyStatements(\n patchTables,\n aslTables,\n Tables.Title,\n ['id', 'content', 'page', 'parent'],\n buildTitlePatchQuery(PATCH_DB_ALIAS, Tables.Title),\n ),\n ]);\n\n return db.batch([detachDB(ASL_DB_ALIAS), detachDB(PATCH_DB_ALIAS)]);\n};\n\nexport const copyTableData = async (db: Client, aslDB: string) => {\n await db.execute(attachDB(aslDB, ASL_DB_ALIAS));\n const tables = await getInternalTables(db, ASL_DB_ALIAS);\n\n logger.debug({ tables }, `Applying patches for...`);\n\n await db.batch([\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title}`,\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page}`,\n ]);\n\n return db.execute(detachDB(ASL_DB_ALIAS));\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,\n `CREATE TABLE title (id INTEGER PRIMARY KEY, content TEXT, page INTEGER, parent INTEGER)`,\n ]);\n};\n\nexport const getAllPages = async (db: Client): Promise<Page[]> => {\n const rows = await selectAllRows(db, Tables.Page);\n\n const pages: Page[] = rows.map((row: any) => {\n const { content, id, number, page, part } = row as PageRow;\n\n return {\n content,\n id,\n ...(page && { page }),\n ...(number && { number }),\n ...(part && { part }),\n };\n });\n\n return pages;\n};\n\nexport const getAllTitles = async (db: Client): Promise<Title[]> => {\n const rows = await selectAllRows(db, Tables.Title);\n\n const titles: Title[] = rows.map((row: any) => {\n const r = row as TitleRow;\n\n return {\n content: r.content,\n id: r.id,\n page: r.page,\n ...(r.parent && { number: r.parent }),\n };\n });\n\n return titles;\n};\n\nexport const getData = async (db: Client): Promise<BookData> => {\n const [pages, titles] = await Promise.all([getAllPages(db), getAllTitles(db)]);\n return { pages, titles };\n};\n","import pino, { Logger } from 'pino';\nimport pretty, { PrettyOptions } from 'pino-pretty';\nimport process from 'process';\n\nconst stream = pretty({\n colorize: true,\n} as PrettyOptions);\n\nconst logger: Logger = pino(\n {\n base: { pid: undefined, hostname: undefined }, // This will remove pid and hostname but keep time\n level: process.env.LOG_LEVEL || 'info',\n },\n stream,\n);\n\nexport default logger;\n","import { Client, Row } from '@libsql/client';\n\nexport type InternalTable = {\n fields: string[];\n name: string;\n};\n\nexport const getInternalTables = async (db: Client, dbName: string): Promise<InternalTable[]> => {\n const { rows: tables } = await db.execute(`SELECT name,sql FROM ${dbName}.sqlite_master WHERE type='table'`);\n\n return tables.map((row: any) => {\n const fields = row.sql.split(', ').map((field: string) => field.split(' ')[0]);\n\n return { fields, name: row.name };\n });\n};\n\nexport const selectAllRows = async (client: Client, table: string): Promise<Row[]> => {\n const { rows } = await client.execute(`SELECT * FROM ${table}`);\n return rows;\n};\n","const MAIN_DB_ALIAS = 'main';\n\nexport const attachDB = (dbFile: string, alias: string) => `ATTACH DATABASE '${dbFile}' AS ${alias}`;\n\nexport const buildPagePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updatePageColumn('content', aslAlias, patchAlias)},\n part = ${updatePageColumn('part', aslAlias, patchAlias)},\n page = ${updatePageColumn('page', aslAlias, patchAlias)},\n number = ${updatePageColumn('number', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nconst updateTitleColumn = (columnName: string, aslAlias: string, patchAlias: string) => `\n (SELECT CASE \n WHEN ${patchAlias}.title.${columnName} != '#' THEN ${patchAlias}.title.${columnName}\n ELSE ${aslAlias}.title.${columnName}\n END \n FROM ${patchAlias}.title\n WHERE ${aslAlias}.title.id = ${patchAlias}.title.id)\n`;\n\nexport const buildTitlePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updateTitleColumn('content', aslAlias, patchAlias)},\n page = ${updateTitleColumn('page', aslAlias, patchAlias)},\n parent = ${updateTitleColumn('parent', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nexport const createTable = (name: string, fields: string[]): string =>\n `CREATE TABLE IF NOT EXISTS ${name} (${fields.join(', ')})`;\n\nexport const detachDB = (alias: string) => `DETACH DATABASE ${alias}`;\n\nconst updatePageColumn = (columnName: string, aslAlias: string, patchAlias: string): string => `\n (SELECT CASE \n WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}\n ELSE ${aslAlias}.page.${columnName}\n END \n FROM ${patchAlias}.page\n WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)\n`;\n\nexport const insertUnsafely = (table: string, fieldToValue: Record<string, any>, isDeleted = false): string => {\n const combinedRecords: Record<string, any> = { ...fieldToValue, is_deleted: isDeleted ? '1' : '0' };\n\n const sortedKeys = Object.keys(combinedRecords).sort();\n\n const sortedValues = sortedKeys.map((key) => combinedRecords[key]);\n\n return `INSERT INTO ${table} (${sortedKeys.toString()}) VALUES (${sortedValues\n .map((val) => {\n if (val === null) {\n return 'NULL';\n }\n\n return typeof val === 'string' ? `'${val}'` : val;\n })\n .toString()})`;\n};\n","export enum Tables {\n Authors = 'authors',\n Books = 'books',\n Categories = 'categories',\n Page = 'page',\n Title = 'title',\n}\n\nexport type AuthorRow = {\n biography: string;\n death: number;\n id: number;\n name: string;\n};\n\nexport type BookRow = {\n author: string;\n bibliography: string;\n category: number;\n date?: null | number;\n hint: null | string;\n id: number;\n major: number;\n metadata: string;\n minor?: number;\n name: string;\n pdf_links: null | string;\n printed: number;\n type: number;\n};\n\nexport type CategoryRow = {\n id: number;\n name: string;\n};\n\nexport type PageRow = {\n content: string;\n id: number;\n number: null | number;\n page: null | number;\n part: null | number;\n};\n\nexport type TitleRow = {\n content: string;\n id: number;\n page: number;\n parent: null | number;\n};\n","import { Client } from '@libsql/client';\nimport path from 'path';\n\nimport { Author, Book, Category, MasterData, PDFLinks } from '../types';\nimport { UNKNOWN_VALUE_PLACEHOLDER } from '../utils/constants';\nimport { selectAllRows } from './common';\nimport { attachDB, detachDB } from './queryBuilder';\nimport { BookRow, Tables } from './types';\n\nexport const copyForeignMasterTableData = async (db: Client, sourceTables: string[]) => {\n const aliasToPath: Record<string, string> = sourceTables.reduce((acc, tablePath) => {\n const { name } = path.parse(tablePath);\n return { ...acc, [name]: tablePath };\n }, {});\n\n const attachStatements: string[] = Object.entries(aliasToPath).map(([alias, dbPath]) => attachDB(dbPath, alias));\n await db.batch(attachStatements);\n\n const insertStatements: string[] = [\n `INSERT INTO ${Tables.Authors} SELECT id,name,biography,(CASE WHEN death_number = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Books} SELECT id,name,category,type,(CASE WHEN date = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Categories} SELECT id,name FROM category WHERE is_deleted='0'`,\n ];\n await db.batch(insertStatements);\n\n const detachStatements: string[] = Object.keys(aliasToPath).map(detachDB);\n await db.batch(detachStatements);\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,\n `CREATE TABLE books (id INTEGER PRIMARY KEY, name TEXT, category INTEGER, type INTEGER, date INTEGER, author TEXT, printed INTEGER, major INTEGER, minor INTEGER, bibliography TEXT, hint TEXT, pdf_links TEXT, metadata TEXT)`,\n `CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)`,\n ]);\n};\n\nexport const getAllAuthors = async (db: Client): Promise<Author[]> => {\n const rows = await selectAllRows(db, Tables.Authors);\n\n const authors: Author[] = rows.map((r: any) => ({\n ...(r.biography && { biography: r.biography }),\n ...(r.death && { death: r.death }),\n id: r.id,\n name: r.name,\n }));\n\n return authors;\n};\n\nexport const getAllBooks = async (db: Client): Promise<Book[]> => {\n const rows = await selectAllRows(db, Tables.Books);\n\n const books: Book[] = rows.map((row: any) => {\n const r = row as BookRow;\n\n return {\n author: parseAuthor(r.author),\n bibliography: r.bibliography,\n category: r.category,\n id: r.id,\n major: r.major,\n metadata: JSON.parse(r.metadata),\n name: r.name,\n printed: r.printed,\n type: r.type,\n ...(r.date && r.date.toString() !== UNKNOWN_VALUE_PLACEHOLDER && { date: r.date }),\n ...(r.hint && { hint: r.hint }),\n ...(r.pdf_links && { pdfLinks: parsePdfLinks(r.pdf_links) }),\n ...(r.minor && { minorRelease: r.minor }),\n };\n });\n\n return books;\n};\n\nexport const getAllCategories = async (db: Client): Promise<Category[]> => {\n const rows = await selectAllRows(db, Tables.Categories);\n\n const categories: Category[] = rows.map((r: any) => ({\n id: r.id,\n name: r.name,\n }));\n\n return categories;\n};\n\nconst parseAuthor = (value: string): number | number[] => {\n const result: number[] = value.split(',\\\\s+').map((id) => parseInt(id.trim()));\n return result.length > 1 ? result : result[0];\n};\n\nconst parsePdfLinks = (value: string): PDFLinks => {\n const result = JSON.parse(value);\n\n if (result.files) {\n result.files = (result.files as string[]).map((f: string) => {\n const [file, id] = f.split('|');\n return { ...(id && { id }), file };\n });\n }\n\n return result as PDFLinks;\n};\n\nexport const getData = async (db: Client): Promise<MasterData> => {\n const [authors, books, categories] = await Promise.all([getAllAuthors(db), getAllBooks(db), getAllCategories(db)]);\n return { authors, books, categories };\n};\n","export const DEFAULT_MASTER_METADATA_VERSION = 0;\n\nexport const UNKNOWN_VALUE_PLACEHOLDER = '99999';\n","import { createWriteStream, promises as fs } from 'fs';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport os from 'os';\nimport path from 'path';\nimport { pipeline } from 'stream/promises';\nimport unzipper, { Entry } from 'unzipper';\n\nexport const createTempDir = async (prefix = 'shamela') => {\n const tempDirBase = path.join(os.tmpdir(), prefix);\n return fs.mkdtemp(tempDirBase);\n};\n\nexport const fileExists = async (path: string) => !!(await fs.stat(path).catch(() => false));\n\n/**\n * Downloads and extracts a ZIP file from a given URL without loading the entire file into memory.\n *\n * @param url - The URL of the ZIP file to download and extract.\n * @param outputDir - The directory where the files should be extracted.\n * @returns A promise that resolves with the list of all extracted files.\n */\nexport async function unzipFromUrl(url: string, outputDir: string): Promise<string[]> {\n const extractedFiles: string[] = [];\n const entryPromises: Promise<void>[] = [];\n\n try {\n // Make HTTPS request and get the response stream\n const response = await new Promise<IncomingMessage>((resolve, reject) => {\n https\n .get(url, (res) => {\n if (res.statusCode !== 200) {\n reject(new Error(`Failed to download ZIP file: ${res.statusCode} ${res.statusMessage}`));\n } else {\n resolve(res);\n }\n })\n .on('error', (err) => {\n reject(new Error(`HTTPS request failed: ${err.message}`));\n });\n });\n\n // Create unzip stream\n const unzipStream = unzipper.Parse();\n\n // Handle entries in the ZIP file\n unzipStream.on('entry', (entry: Entry) => {\n const entryPromise = (async () => {\n const filePath = path.join(outputDir, entry.path);\n\n if (entry.type === 'Directory') {\n // Ensure the directory exists\n await fs.mkdir(filePath, { recursive: true });\n entry.autodrain();\n } else {\n // Ensure the parent directory exists\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n\n // Pipe the entry to a file\n await pipeline(entry, createWriteStream(filePath));\n extractedFiles.push(filePath);\n }\n })().catch((err) => {\n // Emit errors to be handled by the unzipStream error handler\n unzipStream.emit('error', err);\n });\n\n // Collect the promises\n entryPromises.push(entryPromise);\n });\n\n // Handle errors in the unzip stream\n unzipStream.on('error', (err) => {\n throw new Error(`Error during extraction: ${err.message}`);\n });\n\n // Pipe the response into the unzip stream\n await pipeline(response, unzipStream);\n\n // Wait for all entry promises to complete\n await Promise.all(entryPromises);\n\n return extractedFiles;\n } catch (error: any) {\n throw new Error(`Error processing URL: ${error.message}`);\n }\n}\n","import { Buffer } from 'buffer';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nexport const buildUrl = (endpoint: string, params: Record<string, any>, useAuth: boolean = true): URL => {\n const url = new URL(endpoint);\n {\n const params = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n params.append(key, value.toString());\n });\n\n if (useAuth) {\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n }\n\n url.search = params.toString();\n }\n\n return url;\n};\n\nexport const httpsGet = (url: string | URL): Promise<Buffer | Record<string, any>> => {\n return new Promise((resolve, reject) => {\n https\n .get(url, (res: IncomingMessage) => {\n const contentType = res.headers['content-type'] || '';\n const dataChunks: Buffer[] = [];\n\n res.on('data', (chunk: Buffer) => {\n dataChunks.push(chunk);\n });\n\n res.on('end', () => {\n const fullData = Buffer.concat(dataChunks);\n\n if (contentType.includes('application/json')) {\n try {\n const json = JSON.parse(fullData.toString('utf-8'));\n resolve(json);\n } catch (error: any) {\n reject(new Error(`Failed to parse JSON: ${error.message}`));\n }\n } else {\n resolve(fullData);\n }\n });\n })\n .on('error', (error) => {\n reject(new Error(`Error making request: ${error.message}`));\n });\n });\n};\n","import path from 'path';\nimport process from 'process';\n\nconst SOURCE_TABLES = ['author.sqlite', 'book.sqlite', 'category.sqlite'];\n\nexport const validateEnvVariables = () => {\n if (!process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT) {\n throw new Error('SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set');\n }\n\n if (!process.env.SHAMELA_API_KEY) {\n throw new Error('SHAMELA_API_KEY environment variable not set');\n }\n};\n\nexport const validateMasterSourceTables = (sourceTablePaths: string[]) => {\n const sourceTableNames = sourceTablePaths.map((tablePath) => path.parse(tablePath).base);\n return SOURCE_TABLES.every((table) => sourceTableNames.includes(table));\n};\n","export type GetMasterMetadataResponsePayload = {\n url: string;\n version: number;\n};\n\nexport interface OutputOptions {\n path: string;\n}\n\nexport type DownloadMasterOptions = {\n masterMetadata?: GetMasterMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type GetBookMetadataOptions = {\n majorVersion: number;\n minorVersion: number;\n};\n\nexport type GetBookMetadataResponsePayload = {\n majorRelease: number;\n majorReleaseUrl: string;\n minorRelease?: number;\n minorReleaseUrl?: string;\n};\n\nexport type DownloadBookOptions = {\n bookMetadata?: GetBookMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type Author = {\n biography?: string;\n death?: number;\n id: number;\n name: string;\n};\n\ntype PDFFile = {\n file: string;\n id?: string;\n};\n\nexport type PDFLinks = {\n alias?: number;\n cover?: number;\n cover_alias?: number;\n files?: PDFFile[];\n root?: string;\n size?: number;\n};\n\nexport type Metadata = {\n coauthor?: number[];\n date: string;\n group?: number;\n hide_diacritic?: boolean;\n min_ver?: number;\n prefix?: string;\n shorts: Record<string, string>;\n sub_books: number[];\n suffix?: string;\n};\n\nexport type Book = {\n author: number | number[];\n bibliography: string;\n category: number;\n date?: number;\n hint?: string;\n id: number;\n major: number;\n metadata: Metadata;\n minor?: number;\n name: string;\n pdfLinks?: PDFLinks;\n printed: number;\n type: number;\n};\n\nexport type Category = {\n id: number;\n name: string;\n};\n\nexport type MasterData = {\n authors: Author[];\n books: Book[];\n categories: Category[];\n};\n\nexport type Page = {\n content: string;\n id: number;\n number?: number;\n page?: number;\n part?: number;\n};\n\nexport type Title = {\n content: string;\n id: number;\n page: number;\n parent?: number;\n};\n\nexport type BookData = {\n pages: Page[];\n titles?: Title[];\n};\n"],"names":[],"version":3,"file":"main.js.map","sourceRoot":"../"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shamela",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Library to interact with the Maktabah Shamela v4 APIs",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
"source": "src/index.ts",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
15
|
+
"node": ">=22.0.0"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "parcel build",
|
|
19
19
|
"test": "vitest run --coverage",
|
|
20
|
-
"e2e": "
|
|
21
|
-
"e2e:ci": "
|
|
20
|
+
"e2e": "bun run --env-file .env vitest run --coverage --config vitest.e2e.config.ts",
|
|
21
|
+
"e2e:ci": "bun run vitest --config vitest.e2e.config.ts --run"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist/main.js",
|
|
@@ -34,35 +34,34 @@
|
|
|
34
34
|
"author": "Ragaeeb Haq",
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@eslint/js": "^9.
|
|
38
|
-
"@parcel/packager-ts": "^2.
|
|
39
|
-
"@parcel/transformer-typescript-types": "^2.
|
|
37
|
+
"@eslint/js": "^9.17.0",
|
|
38
|
+
"@parcel/packager-ts": "^2.13.3",
|
|
39
|
+
"@parcel/transformer-typescript-types": "^2.13.3",
|
|
40
40
|
"@semantic-release/changelog": "^6.0.3",
|
|
41
41
|
"@semantic-release/git": "^10.0.1",
|
|
42
42
|
"@types/eslint__js": "^8.42.3",
|
|
43
|
-
"@types/node": "^22.
|
|
43
|
+
"@types/node": "^22.10.2",
|
|
44
44
|
"@types/unzipper": "^0.10.10",
|
|
45
|
-
"@vitest/coverage-v8": "^2.1.
|
|
45
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
46
46
|
"dotenv-vault": "^1.26.2",
|
|
47
|
-
"eslint": "^9.
|
|
47
|
+
"eslint": "^9.17.0",
|
|
48
48
|
"eslint-config-prettier": "^9.1.0",
|
|
49
49
|
"eslint-plugin-orderly-functions": "^1.1.0",
|
|
50
|
-
"eslint-plugin-perfectionist": "^
|
|
50
|
+
"eslint-plugin-perfectionist": "^4.4.0",
|
|
51
51
|
"eslint-plugin-prettier": "^5.2.1",
|
|
52
52
|
"eslint-plugin-vitest": "^0.5.4",
|
|
53
53
|
"eslint-plugin-vitest-globals": "^1.5.0",
|
|
54
|
-
"parcel": "^2.
|
|
55
|
-
"prettier": "^3.
|
|
56
|
-
"semantic-release": "^24.
|
|
57
|
-
"typescript": "^5.
|
|
58
|
-
"typescript-eslint": "^8.
|
|
59
|
-
"vitest": "^2.1.
|
|
54
|
+
"parcel": "^2.13.3",
|
|
55
|
+
"prettier": "^3.4.2",
|
|
56
|
+
"semantic-release": "^24.2.0",
|
|
57
|
+
"typescript": "^5.7.2",
|
|
58
|
+
"typescript-eslint": "^8.19.0",
|
|
59
|
+
"vitest": "^2.1.8"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@libsql/client": "^0.14.0",
|
|
63
|
-
"pino": "^9.
|
|
64
|
-
"pino-pretty": "^
|
|
63
|
+
"pino": "^9.6.0",
|
|
64
|
+
"pino-pretty": "^13.0.0",
|
|
65
65
|
"unzipper": "^0.12.3"
|
|
66
|
-
}
|
|
67
|
-
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
|
|
66
|
+
}
|
|
68
67
|
}
|