1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.normalizeURL = exports.chunk = exports.lineSeparatedURLsToSitemapOptions = exports.ReadlineStream = exports.mergeStreams = exports.validateSMIOptions = void 0;
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | const fs_1 = require("fs");
|
10 | const stream_1 = require("stream");
|
11 | const readline_1 = require("readline");
|
12 | const url_1 = require("url");
|
13 | const types_1 = require("./types");
|
14 | const errors_1 = require("./errors");
|
15 | const types_2 = require("./types");
|
16 | function validate(subject, name, url, level) {
|
17 | Object.keys(subject).forEach((key) => {
|
18 |
|
19 |
|
20 | const val = subject[key];
|
21 | if (types_2.validators[key] && !types_2.validators[key].test(val)) {
|
22 | if (level === types_1.ErrorLevel.THROW) {
|
23 | throw new errors_1.InvalidAttrValue(key, val, types_2.validators[key]);
|
24 | }
|
25 | else {
|
26 | console.warn(`${url}: ${name} key ${key} has invalid value: ${val}`);
|
27 | }
|
28 | }
|
29 | });
|
30 | }
|
31 | function handleError(error, level) {
|
32 | if (level === types_1.ErrorLevel.THROW) {
|
33 | throw error;
|
34 | }
|
35 | else if (level === types_1.ErrorLevel.WARN) {
|
36 | console.warn(error.name, error.message);
|
37 | }
|
38 | }
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | function validateSMIOptions(conf, level = types_1.ErrorLevel.WARN, errorHandler = handleError) {
|
46 | if (!conf) {
|
47 | throw new errors_1.NoConfigError();
|
48 | }
|
49 | if (level === types_1.ErrorLevel.SILENT) {
|
50 | return conf;
|
51 | }
|
52 | const { url, changefreq, priority, news, video } = conf;
|
53 | if (!url) {
|
54 | errorHandler(new errors_1.NoURLError(), level);
|
55 | }
|
56 | if (changefreq) {
|
57 | if (!types_1.isValidChangeFreq(changefreq)) {
|
58 | errorHandler(new errors_1.ChangeFreqInvalidError(url, changefreq), level);
|
59 | }
|
60 | }
|
61 | if (priority) {
|
62 | if (!(priority >= 0.0 && priority <= 1.0)) {
|
63 | errorHandler(new errors_1.PriorityInvalidError(url, priority), level);
|
64 | }
|
65 | }
|
66 | if (news) {
|
67 | if (news.access &&
|
68 | news.access !== 'Registration' &&
|
69 | news.access !== 'Subscription') {
|
70 | errorHandler(new errors_1.InvalidNewsAccessValue(url, news.access), level);
|
71 | }
|
72 | if (!news.publication ||
|
73 | !news.publication.name ||
|
74 | !news.publication.language ||
|
75 | !news.publication_date ||
|
76 | !news.title) {
|
77 | errorHandler(new errors_1.InvalidNewsFormat(url), level);
|
78 | }
|
79 | validate(news, 'news', url, level);
|
80 | validate(news.publication, 'publication', url, level);
|
81 | }
|
82 | if (video) {
|
83 | video.forEach((vid) => {
|
84 | var _a;
|
85 | if (vid.duration !== undefined) {
|
86 | if (vid.duration < 0 || vid.duration > 28800) {
|
87 | errorHandler(new errors_1.InvalidVideoDuration(url, vid.duration), level);
|
88 | }
|
89 | }
|
90 | if (vid.rating !== undefined && (vid.rating < 0 || vid.rating > 5)) {
|
91 | errorHandler(new errors_1.InvalidVideoRating(url, vid.title, vid.rating), level);
|
92 | }
|
93 | if (typeof vid !== 'object' ||
|
94 | !vid.thumbnail_loc ||
|
95 | !vid.title ||
|
96 | !vid.description) {
|
97 |
|
98 | errorHandler(new errors_1.InvalidVideoFormat(url), level);
|
99 | }
|
100 | if (vid.title.length > 100) {
|
101 | errorHandler(new errors_1.InvalidVideoTitle(url, vid.title.length), level);
|
102 | }
|
103 | if (vid.description.length > 2048) {
|
104 | errorHandler(new errors_1.InvalidVideoDescription(url, vid.description.length), level);
|
105 | }
|
106 | if (vid.view_count !== undefined && vid.view_count < 0) {
|
107 | errorHandler(new errors_1.InvalidVideoViewCount(url, vid.view_count), level);
|
108 | }
|
109 | if (vid.tag.length > 32) {
|
110 | errorHandler(new errors_1.InvalidVideoTagCount(url, vid.tag.length), level);
|
111 | }
|
112 | if (vid.category !== undefined && ((_a = vid.category) === null || _a === void 0 ? void 0 : _a.length) > 256) {
|
113 | errorHandler(new errors_1.InvalidVideoCategory(url, vid.category.length), level);
|
114 | }
|
115 | if (vid.family_friendly !== undefined &&
|
116 | !types_1.isValidYesNo(vid.family_friendly)) {
|
117 | errorHandler(new errors_1.InvalidVideoFamilyFriendly(url, vid.family_friendly), level);
|
118 | }
|
119 | if (vid.restriction) {
|
120 | if (!types_2.validators.restriction.test(vid.restriction)) {
|
121 | errorHandler(new errors_1.InvalidVideoRestriction(url, vid.restriction), level);
|
122 | }
|
123 | if (!vid['restriction:relationship'] ||
|
124 | !types_1.isAllowDeny(vid['restriction:relationship'])) {
|
125 | errorHandler(new errors_1.InvalidVideoRestrictionRelationship(url, vid['restriction:relationship']), level);
|
126 | }
|
127 | }
|
128 |
|
129 | if ((vid.price === '' && vid['price:type'] === undefined) ||
|
130 | (vid['price:type'] !== undefined && !types_1.isPriceType(vid['price:type']))) {
|
131 | errorHandler(new errors_1.InvalidVideoPriceType(url, vid['price:type'], vid.price), level);
|
132 | }
|
133 | if (vid['price:resolution'] !== undefined &&
|
134 | !types_1.isResolution(vid['price:resolution'])) {
|
135 | errorHandler(new errors_1.InvalidVideoResolution(url, vid['price:resolution']), level);
|
136 | }
|
137 | if (vid['price:currency'] !== undefined &&
|
138 | !types_2.validators['price:currency'].test(vid['price:currency'])) {
|
139 | errorHandler(new errors_1.InvalidVideoPriceCurrency(url, vid['price:currency']), level);
|
140 | }
|
141 | validate(vid, 'video', url, level);
|
142 | });
|
143 | }
|
144 | return conf;
|
145 | }
|
146 | exports.validateSMIOptions = validateSMIOptions;
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | function mergeStreams(streams) {
|
152 | let pass = new stream_1.PassThrough();
|
153 | let waiting = streams.length;
|
154 | for (const stream of streams) {
|
155 | pass = stream.pipe(pass, { end: false });
|
156 | stream.once('end', () => --waiting === 0 && pass.emit('end'));
|
157 | }
|
158 | return pass;
|
159 | }
|
160 | exports.mergeStreams = mergeStreams;
|
161 |
|
162 |
|
163 |
|
164 | class ReadlineStream extends stream_1.Readable {
|
165 | constructor(options) {
|
166 | if (options.autoDestroy === undefined) {
|
167 | options.autoDestroy = true;
|
168 | }
|
169 | options.objectMode = true;
|
170 | super(options);
|
171 | this._source = readline_1.createInterface({
|
172 | input: options.input,
|
173 | terminal: false,
|
174 | crlfDelay: Infinity,
|
175 | });
|
176 |
|
177 | this._source.on('line', (chunk) => {
|
178 |
|
179 | if (!this.push(chunk))
|
180 | this._source.pause();
|
181 | });
|
182 |
|
183 | this._source.on('close', () => {
|
184 | this.push(null);
|
185 | });
|
186 | }
|
187 |
|
188 |
|
189 | _read(size) {
|
190 | this._source.resume();
|
191 | }
|
192 | }
|
193 | exports.ReadlineStream = ReadlineStream;
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | function lineSeparatedURLsToSitemapOptions(stream, { isJSON } = {}) {
|
201 | return new ReadlineStream({ input: stream }).pipe(new stream_1.Transform({
|
202 | objectMode: true,
|
203 |
|
204 | transform: (line, encoding, cb) => {
|
205 | if (isJSON || (isJSON === undefined && line[0] === '{')) {
|
206 | cb(null, JSON.parse(line));
|
207 | }
|
208 | else {
|
209 | cb(null, line);
|
210 | }
|
211 | },
|
212 | }));
|
213 | }
|
214 | exports.lineSeparatedURLsToSitemapOptions = lineSeparatedURLsToSitemapOptions;
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 | function chunk(array, size = 1) {
|
229 | size = Math.max(Math.trunc(size), 0);
|
230 | const length = array ? array.length : 0;
|
231 | if (!length || size < 1) {
|
232 | return [];
|
233 | }
|
234 | const result = Array(Math.ceil(length / size));
|
235 | let index = 0, resIndex = 0;
|
236 | while (index < length) {
|
237 | result[resIndex++] = array.slice(index, (index += size));
|
238 | }
|
239 | return result;
|
240 | }
|
241 | exports.chunk = chunk;
|
242 | function boolToYESNO(bool) {
|
243 | if (bool === undefined) {
|
244 | return bool;
|
245 | }
|
246 | if (typeof bool === 'boolean') {
|
247 | return bool ? types_1.EnumYesNo.yes : types_1.EnumYesNo.no;
|
248 | }
|
249 | return bool;
|
250 | }
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | function normalizeURL(elem, hostname, lastmodDateOnly = false) {
|
258 |
|
259 |
|
260 | let smi = {
|
261 | img: [],
|
262 | video: [],
|
263 | links: [],
|
264 | url: '',
|
265 | };
|
266 | let smiLoose;
|
267 | if (typeof elem === 'string') {
|
268 | smi.url = elem;
|
269 | smiLoose = { url: elem };
|
270 | }
|
271 | else {
|
272 | smiLoose = elem;
|
273 | }
|
274 | smi.url = new url_1.URL(smiLoose.url, hostname).toString();
|
275 | let img = [];
|
276 | if (smiLoose.img) {
|
277 | if (typeof smiLoose.img === 'string') {
|
278 |
|
279 | smiLoose.img = [{ url: smiLoose.img }];
|
280 | }
|
281 | else if (!Array.isArray(smiLoose.img)) {
|
282 |
|
283 | smiLoose.img = [smiLoose.img];
|
284 | }
|
285 | img = smiLoose.img.map((el) => (typeof el === 'string' ? { url: el } : el));
|
286 | }
|
287 |
|
288 | smi.img = img.map((el) => ({
|
289 | ...el,
|
290 | url: new url_1.URL(el.url, hostname).toString(),
|
291 | }));
|
292 | let links = [];
|
293 | if (smiLoose.links) {
|
294 | links = smiLoose.links;
|
295 | }
|
296 | smi.links = links.map((link) => {
|
297 | return { ...link, url: new url_1.URL(link.url, hostname).toString() };
|
298 | });
|
299 | if (smiLoose.video) {
|
300 | if (!Array.isArray(smiLoose.video)) {
|
301 |
|
302 | smiLoose.video = [smiLoose.video];
|
303 | }
|
304 | smi.video = smiLoose.video.map((video) => {
|
305 | const nv = {
|
306 | ...video,
|
307 | family_friendly: boolToYESNO(video.family_friendly),
|
308 | live: boolToYESNO(video.live),
|
309 | requires_subscription: boolToYESNO(video.requires_subscription),
|
310 | tag: [],
|
311 | rating: undefined,
|
312 | };
|
313 | if (video.tag !== undefined) {
|
314 | nv.tag = !Array.isArray(video.tag) ? [video.tag] : video.tag;
|
315 | }
|
316 | if (video.rating !== undefined) {
|
317 | if (typeof video.rating === 'string') {
|
318 | nv.rating = parseFloat(video.rating);
|
319 | }
|
320 | else {
|
321 | nv.rating = video.rating;
|
322 | }
|
323 | }
|
324 | if (typeof video.view_count === 'string') {
|
325 | nv.view_count = parseInt(video.view_count, 10);
|
326 | }
|
327 | else if (typeof video.view_count === 'number') {
|
328 | nv.view_count = video.view_count;
|
329 | }
|
330 | return nv;
|
331 | });
|
332 | }
|
333 |
|
334 | if (smiLoose.lastmodfile) {
|
335 | const { mtime } = fs_1.statSync(smiLoose.lastmodfile);
|
336 | smi.lastmod = new Date(mtime).toISOString();
|
337 |
|
338 | }
|
339 | else if (smiLoose.lastmodISO) {
|
340 | smi.lastmod = new Date(smiLoose.lastmodISO).toISOString();
|
341 | }
|
342 | else if (smiLoose.lastmod) {
|
343 | smi.lastmod = new Date(smiLoose.lastmod).toISOString();
|
344 | }
|
345 | if (lastmodDateOnly && smi.lastmod) {
|
346 | smi.lastmod = smi.lastmod.slice(0, 10);
|
347 | }
|
348 | delete smiLoose.lastmodfile;
|
349 | delete smiLoose.lastmodISO;
|
350 | smi = { ...smiLoose, ...smi };
|
351 | return smi;
|
352 | }
|
353 | exports.normalizeURL = normalizeURL;
|