node-csfd-api 3.0.0-next.2 → 3.0.0-next.21

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.
Files changed (67) hide show
  1. package/README.md +103 -45
  2. package/fetchers/fetch.polyfill.d.ts +1 -0
  3. package/fetchers/fetch.polyfill.js +9 -0
  4. package/{cjs/fetchers → fetchers}/index.js +5 -14
  5. package/helpers/cinema.helper.d.ts +19 -0
  6. package/helpers/cinema.helper.js +105 -0
  7. package/{cjs/helpers → helpers}/creator.helper.js +12 -11
  8. package/{types/helpers → helpers}/global.helper.d.ts +10 -0
  9. package/{cjs/helpers → helpers}/global.helper.js +9 -5
  10. package/{cjs/helpers → helpers}/movie.helper.js +9 -4
  11. package/{types/helpers → helpers}/search.helper.d.ts +1 -1
  12. package/{cjs/helpers → helpers}/search.helper.js +5 -3
  13. package/{cjs/helpers → helpers}/user-ratings.helper.js +2 -1
  14. package/{types/index.d.ts → index.d.ts} +5 -1
  15. package/index.js +39 -0
  16. package/interfaces/cinema.interface.d.ts +23 -0
  17. package/interfaces/user-ratings.interface.js +2 -0
  18. package/package.json +21 -14
  19. package/services/cinema.service.d.ts +6 -0
  20. package/services/cinema.service.js +34 -0
  21. package/services/creator.service.js +32 -0
  22. package/{cjs/services → services}/movie.service.js +10 -21
  23. package/{cjs/services → services}/search.service.js +29 -20
  24. package/{cjs/services → services}/user-ratings.service.js +25 -36
  25. package/{types/vars.d.ts → vars.d.ts} +2 -0
  26. package/{cjs/vars.js → vars.js} +5 -1
  27. package/cjs/index.js +0 -50
  28. package/cjs/services/creator.service.js +0 -43
  29. package/esm/fetchers/index.js +0 -32
  30. package/esm/helpers/creator.helper.js +0 -73
  31. package/esm/helpers/global.helper.js +0 -56
  32. package/esm/helpers/movie.helper.js +0 -223
  33. package/esm/helpers/search-user.helper.js +0 -15
  34. package/esm/helpers/search.helper.js +0 -49
  35. package/esm/helpers/user-ratings.helper.js +0 -47
  36. package/esm/index.js +0 -46
  37. package/esm/interfaces/creator.interface.js +0 -1
  38. package/esm/interfaces/global.js +0 -1
  39. package/esm/interfaces/movie.interface.js +0 -1
  40. package/esm/interfaces/search.interface.js +0 -1
  41. package/esm/interfaces/user-ratings.interface.js +0 -1
  42. package/esm/services/creator.service.js +0 -39
  43. package/esm/services/movie.service.js +0 -65
  44. package/esm/services/search.service.js +0 -67
  45. package/esm/services/user-ratings.service.js +0 -91
  46. package/esm/vars.js +0 -4
  47. package/types/index.ts +0 -22
  48. /package/{types/fetchers → fetchers}/index.d.ts +0 -0
  49. /package/{types/helpers → helpers}/creator.helper.d.ts +0 -0
  50. /package/{types/helpers → helpers}/movie.helper.d.ts +0 -0
  51. /package/{types/helpers → helpers}/search-user.helper.d.ts +0 -0
  52. /package/{cjs/helpers → helpers}/search-user.helper.js +0 -0
  53. /package/{types/helpers → helpers}/user-ratings.helper.d.ts +0 -0
  54. /package/{cjs/interfaces/creator.interface.js → interfaces/cinema.interface.js} +0 -0
  55. /package/{types/interfaces → interfaces}/creator.interface.d.ts +0 -0
  56. /package/{cjs/interfaces/global.js → interfaces/creator.interface.js} +0 -0
  57. /package/{types/interfaces → interfaces}/global.d.ts +0 -0
  58. /package/{cjs/interfaces/movie.interface.js → interfaces/global.js} +0 -0
  59. /package/{types/interfaces → interfaces}/movie.interface.d.ts +0 -0
  60. /package/{cjs/interfaces/search.interface.js → interfaces/movie.interface.js} +0 -0
  61. /package/{types/interfaces → interfaces}/search.interface.d.ts +0 -0
  62. /package/{cjs/interfaces/user-ratings.interface.js → interfaces/search.interface.js} +0 -0
  63. /package/{types/interfaces → interfaces}/user-ratings.interface.d.ts +0 -0
  64. /package/{types/services → services}/creator.service.d.ts +0 -0
  65. /package/{types/services → services}/movie.service.d.ts +0 -0
  66. /package/{types/services → services}/search.service.d.ts +0 -0
  67. /package/{types/services → services}/user-ratings.service.d.ts +0 -0
package/README.md CHANGED
@@ -3,29 +3,31 @@
3
3
  [![Build & Publish](https://github.com/bartholomej/node-csfd-api/workflows/Publish/badge.svg)](https://github.com/bartholomej/node-csfd-api/actions)
4
4
  [![codecov](https://codecov.io/gh/bartholomej/node-csfd-api/branch/master/graph/badge.svg?token=YQH9UoVrGP)](https://codecov.io/gh/bartholomej/node-csfd-api)
5
5
 
6
- # CSFD API 2022
6
+ # CSFD API 🎥 2025
7
7
 
8
8
  > JavaScript NPM library for scraping **Czech Movie Database (csfd.cz)**
9
9
  >
10
- > - Browser + Node.js (SSR)
11
10
  > - JavaScript / TypeScript
11
+ > - Browser + Node.js (SSR)
12
12
  > - Tested (~100% Code coverage)
13
- > - ✅ Ready for new ČSFD 2021!
13
+ > - ✅ Ready for new ČSFD 2025!
14
14
  > - You can use in:
15
+ > - Docker – [_How to do it?_](#-docker)
15
16
  > - Firebase function
16
17
  > - AWS λ (lambda function)
18
+ > - CloudFlare Worker
17
19
  > - Chrome extension
18
20
  > - React native app
19
- > - ...
21
+ > - Browsers (Pay attention to CORS)
20
22
 
21
- ## Install
23
+ ## 🗜️ Install
22
24
 
23
25
  ```bash
24
- npm install node-csfd-api --save
26
+ npm install node-csfd-api
25
27
  # yarn add node-csfd-api
26
28
  ```
27
29
 
28
- ## Usage and examples
30
+ ## 🛠️ Usage and examples
29
31
 
30
32
  - [Movies and TV Series](#Movie)
31
33
  - [User Ratings](#User-Ratings)
@@ -34,7 +36,7 @@ npm install node-csfd-api --save
34
36
 
35
37
  ### Movie
36
38
 
37
- Get info about [this movie](https://www.csfd.cz/film/535121-na-spatne-strane/komentare/) _(id: 535121)_
39
+ > Get info about [this movie](https://www.csfd.cz/film/535121-na-spatne-strane/komentare/) _(id: 535121)_
38
40
 
39
41
  ```javascript
40
42
  import { csfd } from 'node-csfd-api';
@@ -42,8 +44,9 @@ import { csfd } from 'node-csfd-api';
42
44
  csfd.movie(535121).then((movie) => console.log(movie));
43
45
  ```
44
46
 
45
- #### Results
46
-
47
+ <details>
48
+ <summary>Click here to see full result example</summary>
49
+
47
50
  ```javascript
48
51
  {
49
52
  id: 535121,
@@ -135,10 +138,11 @@ csfd.movie(535121).then((movie) => console.log(movie));
135
138
  ]
136
139
  }
137
140
  ```
141
+ </details>
138
142
 
139
143
  ### Search
140
144
 
141
- > Search movies and users
145
+ > Search movies, users and TV series
142
146
 
143
147
  ```javascript
144
148
  import { csfd } from 'node-csfd-api';
@@ -146,10 +150,11 @@ import { csfd } from 'node-csfd-api';
146
150
  csfd.search('bart').then((search) => console.log(search));
147
151
  ```
148
152
 
149
- #### Results
150
-
153
+ <details>
154
+ <summary>Click here to see full result example</summary>
155
+
151
156
  ```javascript
152
- movies: [
157
+ [
153
158
  {
154
159
  id: 19653,
155
160
  title: 'Black Bart',
@@ -173,6 +178,19 @@ movies: [
173
178
  }
174
179
  }
175
180
  ],
181
+ tvSeries: [
182
+ {
183
+ id: 71924,
184
+ title: 'Království',
185
+ year: 1994,
186
+ url: 'https://www.csfd.cz/film/71924-kralovstvi/',
187
+ type: 'seriál',
188
+ colorRating: 'good',
189
+ poster: 'https://image.pmgstatic.com/cache/resized/w60h85/files/images/film/posters/166/708/166708064_2da697.jpg',
190
+ origins: ['Dánsko'],
191
+ creators: []
192
+ }
193
+ ],
176
194
  users: [
177
195
  {
178
196
  id: 912,
@@ -184,9 +202,11 @@ users: [
184
202
  ]
185
203
  ```
186
204
 
205
+ </details>
206
+
187
207
  ### Creators
188
208
 
189
- > Search creators and filmography
209
+ > Get creator info + filmography
190
210
 
191
211
  ```javascript
192
212
  import { csfd } from 'node-csfd-api';
@@ -194,7 +214,8 @@ import { csfd } from 'node-csfd-api';
194
214
  csfd.creator(2120).then((creator) => console.log(creator));
195
215
  ```
196
216
 
197
- #### Results
217
+ <details>
218
+ <summary>Click here to see full result example</summary>
198
219
 
199
220
  ```javascript
200
221
  {
@@ -271,6 +292,8 @@ csfd.creator(2120).then((creator) => console.log(creator));
271
292
  }
272
293
  ```
273
294
 
295
+ </details>
296
+
274
297
  ### User Ratings
275
298
 
276
299
  #### Last ratings (last page)
@@ -300,7 +323,8 @@ csfd
300
323
  .then((ratings) => console.log(ratings));
301
324
  ```
302
325
 
303
- #### Results
326
+ <details>
327
+ <summary>Click here to see full result example</summary>
304
328
 
305
329
  ```javascript
306
330
  [
@@ -325,7 +349,9 @@ csfd
325
349
  ];
326
350
  ```
327
351
 
328
- #### Options
352
+ </details>
353
+
354
+ #### Options for user ratings
329
355
 
330
356
  | Option | Type | Default | Description |
331
357
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ------------------------------------------------------ |
@@ -334,15 +360,62 @@ csfd
334
360
  | **allPages** | boolean | false | Get all pages |
335
361
  | **allPagesDelay** | number | 0 | Delay on each page request. In milliseconds |
336
362
 
337
- _Note: You can not use both parameters 'includesOnly' and 'excludes'. Parameter 'includesOnly' has a priority._
363
+ _Note: You can not use both parameters `includesOnly` and `excludes`. Parameter `includesOnly` has a priority._
364
+
365
+ ## 📦 Docker
366
+
367
+ You can use this library in Docker.
338
368
 
339
- ## Used by
369
+ We have [prepared a Docker image](https://hub.docker.com/r/bartholomej/node-csfd-api) for you.
340
370
 
341
- - [Dafilms web extension](https://chrome.google.com/webstore/detail/dafilms/hgcgneddmgflnbmhkjnefiobjgobbmdm?hl=en) ([code](https://github.com/bartholomej/dafilms-ext)) – Parser for film ratings (web extension)
342
- - [bartweb.cz](https://bartweb.cz) – **Last seen** section (Firebase function)
343
- - KinoKlub – Mobile application for AeroFilms (native Android + iOS application)
371
+ ### Prebuilt image
372
+
373
+ ```bash
374
+ docker pull bartholomej/node-csfd-api
375
+ ```
376
+
377
+ ### Build & run your own image
378
+
379
+ > Build image
380
+
381
+ ```bash
382
+ docker build -t node-csfd-api .
383
+ ```
344
384
 
345
- ## Roadmap
385
+ > Run image on port 3000
386
+
387
+ ```bash
388
+ docker run -p 3000:3000 node-csfd-api
389
+ ```
390
+
391
+ > Open http://localhost:3000
392
+
393
+ ### API endpoints
394
+
395
+ > Some examples
396
+
397
+ - `/movie/535121`
398
+ - `/search/quentin+tarantino`
399
+ - `/creator/2120`
400
+ - `/user-ratings/912-bart`
401
+
402
+ ## 🧑‍💻 Used by
403
+
404
+ ### Web extensions
405
+
406
+ - [Netflix: chrome extension](https://chrome.google.com/webstore/detail/netflix-csfd/eomgekccbddnlpmehgdjmlphndjgnlni) ([code](https://github.com/bartholomej/netflix-csfd-ext))
407
+ - [Dafilms: chrome extension](https://chrome.google.com/webstore/detail/dafilms/hgcgneddmgflnbmhkjnefiobjgobbmdm) ([code](https://github.com/bartholomej/dafilms-ext))
408
+ - [Kviff.tv: chrome extension](https://chrome.google.com/webstore/detail/kvifftv-%20-csfd/ihpngekoejodiligajlppbeedofhnmfm) ([code](https://github.com/bartholomej/kviff-ext))
409
+
410
+ ### Web applications
411
+
412
+ - [bartweb.cz](https://bartweb.cz) – **Last seen** section (**Firebase function**)
413
+
414
+ ### Mobile applications
415
+
416
+ - [KinoKlub](https://play.google.com/store/apps/details?id=com.aquasoup) – Mobile application for AeroFilms (React Native: Android + iOS application)
417
+
418
+ ## 🔮 Roadmap
346
419
 
347
420
  ### Scraping more pages
348
421
 
@@ -381,8 +454,8 @@ _Note: You can not use both parameters 'includesOnly' and 'excludes'. Parameter
381
454
  - [ ] Search
382
455
  - [x] Movies
383
456
  - [x] Users
457
+ - [x] TV Series
384
458
  - [ ] Creators
385
- - [ ] TV Series
386
459
  - [x] Creators
387
460
  - [x] Bio
388
461
  - [x] Movies (TODO categories)
@@ -390,7 +463,7 @@ _Note: You can not use both parameters 'includesOnly' and 'excludes'. Parameter
390
463
  - [x] Last ratings
391
464
  - [x] All pages
392
465
 
393
- ## Development
466
+ ## 🛠️ Development
394
467
 
395
468
  ### Developing and debugging library
396
469
 
@@ -406,22 +479,7 @@ You can find and modify it in [`./demo.ts`](https://github.com/bartholomej/node-
406
479
  yarn demo
407
480
  ```
408
481
 
409
- ## Development (notes for me)
410
-
411
- ### Publish Stable
412
-
413
- ```shell
414
- yarn release:patch
415
- # yarn release:minor
416
- # yarn release:major
417
- ```
418
-
419
- ### Publish next channel
420
-
421
- 1. Bump version `-beta.0` in `package.json`
422
- 2. `yarn release:beta`
423
-
424
- ## Contribution
482
+ ## 🤝 Contribution
425
483
 
426
484
  I welcome you to customize this according to your needs ;)
427
485
 
@@ -433,7 +491,7 @@ Give a ⭐️ if this project helped you!
433
491
 
434
492
  Or if you are brave enough consider [making a donation](https://github.com/sponsors/bartholomej) for some 🍺 or 🍵 ;)
435
493
 
436
- ## Privacy Policy
494
+ ## 🕵️‍♀️ Privacy Policy
437
495
 
438
496
  I DO NOT STORE ANY DATA. PERIOD.
439
497
 
@@ -441,9 +499,9 @@ I physically can't. I have nowhere to store it. I don't even have a server datab
441
499
 
442
500
  That's why, with node-csfd-api, what happens on your device stays on your device till disappear.
443
501
 
444
- ## License
502
+ ## 📝 License
445
503
 
446
- Copyright &copy; 2022 [Lukas Bartak](http://bartweb.cz)
504
+ Copyright &copy; 2020 – 2025 [Lukas Bartak](http://bartweb.cz)
447
505
 
448
506
  Proudly powered by nature 🗻, wind 💨, tea 🍵 and beer 🍺 ;)
449
507
 
@@ -0,0 +1 @@
1
+ export declare const fetchSafe: typeof fetch;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchSafe = void 0;
4
+ // Check if `fetch` is available in global scope (nodejs 18+) or in window (browser). If not, use cross-fetch polyfill.
5
+ const cross_fetch_1 = require("cross-fetch");
6
+ exports.fetchSafe = (typeof fetch === 'function' && fetch) || // ServiceWorker fetch (Cloud Functions + Chrome extension)
7
+ (typeof global === 'object' && global.fetch) || // Node.js 18+ fetch
8
+ (typeof window !== 'undefined' && window.fetch) || // Browser fetch
9
+ cross_fetch_1.fetch; // Polyfill fetch
@@ -1,16 +1,7 @@
1
1
  "use strict";
2
- // import fetch from 'cross-fetch';
3
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
- return new (P || (P = Promise))(function (resolve, reject) {
6
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
- step((generator = generator.apply(thisArg, _arguments || [])).next());
10
- });
11
- };
12
2
  Object.defineProperty(exports, "__esModule", { value: true });
13
3
  exports.fetchPage = void 0;
4
+ const fetch_polyfill_1 = require("./fetch.polyfill");
14
5
  const USER_AGENTS = [
15
6
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
16
7
  'Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1',
@@ -20,17 +11,17 @@ const USER_AGENTS = [
20
11
  const headers = {
21
12
  'User-Agent': USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)]
22
13
  };
23
- const fetchPage = (url) => __awaiter(void 0, void 0, void 0, function* () {
14
+ const fetchPage = async (url) => {
24
15
  try {
25
- const response = yield fetch(url, { headers });
16
+ const response = await (0, fetch_polyfill_1.fetchSafe)(url, { headers });
26
17
  if (response.status >= 400 && response.status < 600) {
27
18
  throw new Error(`node-csfd-api: Bad response ${response.status} for url: ${url}`);
28
19
  }
29
- return yield response.text();
20
+ return await response.text();
30
21
  }
31
22
  catch (e) {
32
23
  console.error(e);
33
24
  return 'Error';
34
25
  }
35
- });
26
+ };
36
27
  exports.fetchPage = fetchPage;
@@ -0,0 +1,19 @@
1
+ import { CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie } from 'interfaces/cinema.interface';
2
+ import { HTMLElement } from 'node-html-parser';
3
+ import { CSFDColorRating } from '../interfaces/global';
4
+ export declare const getColorRating: (el: HTMLElement) => CSFDColorRating;
5
+ export declare const getCinemaId: (el: HTMLElement | null) => number;
6
+ export declare const getId: (url: string) => number;
7
+ export declare const getName: (el: HTMLElement | null) => string;
8
+ export declare const getCoords: (el: HTMLElement | null) => {
9
+ lat: number;
10
+ lng: number;
11
+ };
12
+ export declare const getCinemaUrl: (el: HTMLElement | null) => string;
13
+ export declare const parseCinema: (el: HTMLElement | null) => {
14
+ city: string;
15
+ name: string;
16
+ };
17
+ export declare const getGroupedFilmsByDate: (el: HTMLElement | null) => CSFDCinemaGroupedFilmsByDate[];
18
+ export declare const getFilms: (date: string, el: HTMLElement | null) => CSFDCinemaMovie[];
19
+ export declare const parseMeta: (meta: string[]) => CSFDCinemaMeta[];
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMeta = exports.getFilms = exports.getGroupedFilmsByDate = exports.parseCinema = exports.getCinemaUrl = exports.getCoords = exports.getName = exports.getId = exports.getCinemaId = exports.getColorRating = void 0;
4
+ const global_helper_1 = require("./global.helper");
5
+ const getColorRating = (el) => {
6
+ return (0, global_helper_1.parseColor)(el === null || el === void 0 ? void 0 : el.classNames.split(' ').pop());
7
+ };
8
+ exports.getColorRating = getColorRating;
9
+ const getCinemaId = (el) => {
10
+ var _a;
11
+ const id = (_a = el === null || el === void 0 ? void 0 : el.id) === null || _a === void 0 ? void 0 : _a.split('-')[1];
12
+ return +id;
13
+ };
14
+ exports.getCinemaId = getCinemaId;
15
+ const getId = (url) => {
16
+ if (url) {
17
+ return (0, global_helper_1.parseIdFromUrl)(url);
18
+ }
19
+ return null;
20
+ };
21
+ exports.getId = getId;
22
+ const getName = (el) => {
23
+ return el.querySelector('h1').innerText.trim();
24
+ };
25
+ exports.getName = getName;
26
+ const getCoords = (el) => {
27
+ const linkMapsEl = el.querySelector('a[href*="q="]');
28
+ if (!linkMapsEl)
29
+ return null;
30
+ const linkMaps = linkMapsEl.getAttribute('href');
31
+ const [_, latLng] = linkMaps.split('q=');
32
+ const coords = latLng.split(',');
33
+ if (coords.length !== 2)
34
+ return null;
35
+ const lat = Number(coords[0]);
36
+ const lng = Number(coords[1]);
37
+ if (Number.isFinite(lat) && Number.isFinite(lng)) {
38
+ return { lat, lng };
39
+ }
40
+ return null;
41
+ };
42
+ exports.getCoords = getCoords;
43
+ const getCinemaUrl = (el) => {
44
+ var _a, _b;
45
+ return (_b = (_a = el.querySelector('a[title="Přejít na webovou stránku kina"]')) === null || _a === void 0 ? void 0 : _a.attributes.href) !== null && _b !== void 0 ? _b : '';
46
+ };
47
+ exports.getCinemaUrl = getCinemaUrl;
48
+ const parseCinema = (el) => {
49
+ const title = el.querySelector('.box-header h2').innerText.trim();
50
+ const [city, name] = title.split(' - ');
51
+ return { city, name };
52
+ };
53
+ exports.parseCinema = parseCinema;
54
+ const getGroupedFilmsByDate = (el) => {
55
+ const divs = el.querySelectorAll(':scope > div');
56
+ const getDatesAndFilms = divs
57
+ .map((_, index) => index)
58
+ .filter((index) => index % 2 === 0)
59
+ .map((index) => {
60
+ var _a, _b, _c;
61
+ const [date, films] = divs.slice(index, index + 2);
62
+ const dateText = (_c = (_b = (_a = date === null || date === void 0 ? void 0 : date.firstChild) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : "";
63
+ return { date: dateText, films: (0, exports.getFilms)('', films) };
64
+ });
65
+ return getDatesAndFilms;
66
+ };
67
+ exports.getGroupedFilmsByDate = getGroupedFilmsByDate;
68
+ const getFilms = (date, el) => {
69
+ const filmNodes = el.querySelectorAll('.cinema-table tr');
70
+ const films = filmNodes.map((filmNode) => {
71
+ var _a, _b, _c, _d;
72
+ const url = (_a = filmNode.querySelector('td.name h3 a')) === null || _a === void 0 ? void 0 : _a.attributes.href;
73
+ const id = (0, exports.getId)(url);
74
+ const title = (_b = filmNode.querySelector('.name h3')) === null || _b === void 0 ? void 0 : _b.text.trim();
75
+ const colorRating = (0, exports.getColorRating)(filmNode.querySelector('.name .icon'));
76
+ const showTimes = (_c = filmNode.querySelectorAll('.td-time')) === null || _c === void 0 ? void 0 : _c.map((x) => x.textContent.trim());
77
+ const meta = (_d = filmNode.querySelectorAll('.td-title span')) === null || _d === void 0 ? void 0 : _d.map((x) => x.text.trim());
78
+ return {
79
+ id,
80
+ title,
81
+ url,
82
+ colorRating,
83
+ showTimes,
84
+ meta: (0, exports.parseMeta)(meta)
85
+ };
86
+ });
87
+ return films;
88
+ };
89
+ exports.getFilms = getFilms;
90
+ const parseMeta = (meta) => {
91
+ const metaConvert = [];
92
+ for (const element of meta) {
93
+ if (element === 'T') {
94
+ metaConvert.push('subtitles');
95
+ }
96
+ else if (element === 'D') {
97
+ metaConvert.push('dubbing');
98
+ }
99
+ else {
100
+ metaConvert.push(element);
101
+ }
102
+ }
103
+ return metaConvert;
104
+ };
105
+ exports.parseMeta = parseMeta;
@@ -18,24 +18,25 @@ const getName = (el) => {
18
18
  };
19
19
  exports.getName = getName;
20
20
  const getBirthdayInfo = (el) => {
21
- const text = el.querySelector('h1 + p').innerHTML.trim();
22
- const parts = text.split('\n');
23
- let birthday;
24
- let age;
25
- let birthPlace;
26
- if (parts.length) {
21
+ var _a, _b;
22
+ const infoBlock = el.querySelector('h1 + p');
23
+ const text = infoBlock === null || infoBlock === void 0 ? void 0 : infoBlock.innerHTML.trim();
24
+ const birthPlaceRow = (_a = infoBlock === null || infoBlock === void 0 ? void 0 : infoBlock.querySelector('.info-place')) === null || _a === void 0 ? void 0 : _a.innerHTML.trim();
25
+ const ageRow = (_b = infoBlock === null || infoBlock === void 0 ? void 0 : infoBlock.querySelector('.info')) === null || _b === void 0 ? void 0 : _b.innerHTML.trim();
26
+ let birthday = '';
27
+ if (text) {
28
+ const parts = text.split('\n');
27
29
  const birthdayRow = parts.find((x) => x.includes('nar.'));
28
- const ageRow = parts.find((x) => x.includes('let)'));
29
- const birthPlaceRow = parts.find((x) => x.includes('<br>')); // Ugly but there is no other way to detect
30
30
  birthday = birthdayRow ? (0, exports.parseBirthday)(birthdayRow) : '';
31
- age = ageRow ? +(0, exports.parseAge)(ageRow) : null;
32
- birthPlace = birthPlaceRow ? (0, exports.parseBirthPlace)(birthPlaceRow) : '';
33
31
  }
32
+ const age = ageRow ? +(0, exports.parseAge)(ageRow) : null;
33
+ const birthPlace = birthPlaceRow ? (0, exports.parseBirthPlace)(birthPlaceRow) : '';
34
34
  return { birthday, age, birthPlace };
35
35
  };
36
36
  exports.getBirthdayInfo = getBirthdayInfo;
37
37
  const getBio = (el) => {
38
- return el.querySelector('.article-content p').text.trim().split('\n')[0].trim();
38
+ var _a;
39
+ return ((_a = el.querySelector('.article-content p')) === null || _a === void 0 ? void 0 : _a.text.trim().split('\n')[0].trim()) || null;
39
40
  };
40
41
  exports.getBio = getBio;
41
42
  const getPhoto = (el) => {
@@ -4,4 +4,14 @@ export declare const parseIdFromUrl: (url: string) => number;
4
4
  export declare const getColor: (cls: string) => CSFDColorRating;
5
5
  export declare const parseColor: (quality: Colors) => CSFDColorRating;
6
6
  export declare const addProtocol: (url: string) => string;
7
+ export declare const getDuration: (matches: any[]) => {
8
+ sign: string;
9
+ years: any;
10
+ months: any;
11
+ weeks: any;
12
+ days: any;
13
+ hours: any;
14
+ minutes: any;
15
+ seconds: any;
16
+ };
7
17
  export declare const parseISO8601Duration: (iso: string) => number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseISO8601Duration = exports.addProtocol = exports.parseColor = exports.getColor = exports.parseIdFromUrl = void 0;
3
+ exports.parseISO8601Duration = exports.getDuration = exports.addProtocol = exports.parseColor = exports.getColor = exports.parseIdFromUrl = void 0;
4
4
  const parseIdFromUrl = (url) => {
5
5
  if (url) {
6
6
  const idSlug = url === null || url === void 0 ? void 0 : url.split('/')[2];
@@ -46,10 +46,8 @@ const addProtocol = (url) => {
46
46
  return url.startsWith('//') ? 'https:' + url : url;
47
47
  };
48
48
  exports.addProtocol = addProtocol;
49
- const parseISO8601Duration = (iso) => {
50
- const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
51
- const matches = iso.match(iso8601DurationRegex);
52
- const duration = {
49
+ const getDuration = (matches) => {
50
+ return {
53
51
  sign: matches[1] === undefined ? '+' : '-',
54
52
  years: matches[2] === undefined ? 0 : matches[2],
55
53
  months: matches[3] === undefined ? 0 : matches[3],
@@ -59,6 +57,12 @@ const parseISO8601Duration = (iso) => {
59
57
  minutes: matches[7] === undefined ? 0 : matches[7],
60
58
  seconds: matches[8] === undefined ? 0 : matches[8]
61
59
  };
60
+ };
61
+ exports.getDuration = getDuration;
62
+ const parseISO8601Duration = (iso) => {
63
+ const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
64
+ const matches = iso.match(iso8601DurationRegex);
65
+ const duration = (0, exports.getDuration)(matches);
62
66
  return +duration.minutes;
63
67
  };
64
68
  exports.parseISO8601Duration = parseISO8601Duration;
@@ -28,9 +28,10 @@ const getColorRating = (bodyClasses) => {
28
28
  exports.getColorRating = getColorRating;
29
29
  const getRating = (el) => {
30
30
  const ratingRaw = el.querySelector('.film-rating-average').textContent;
31
- const rating = +(ratingRaw === null || ratingRaw === void 0 ? void 0 : ratingRaw.replace(/%/g, '').trim());
32
- if (Number.isInteger(rating)) {
33
- return rating;
31
+ const rating = ratingRaw === null || ratingRaw === void 0 ? void 0 : ratingRaw.replace(/%/g, '').trim();
32
+ const ratingInt = parseInt(rating);
33
+ if (Number.isInteger(ratingInt)) {
34
+ return ratingInt;
34
35
  }
35
36
  else {
36
37
  return null;
@@ -90,7 +91,10 @@ const getDuration = (jsonLdRaw, el) => {
90
91
  exports.getDuration = getDuration;
91
92
  const getTitlesOther = (el) => {
92
93
  const namesNode = el.querySelectorAll('.film-names li');
93
- return namesNode.map((el) => {
94
+ if (!namesNode.length) {
95
+ return [];
96
+ }
97
+ const titlesOther = namesNode.map((el) => {
94
98
  const country = el.querySelector('img.flag').attributes.alt;
95
99
  const title = el.textContent.trim().split('\n')[0];
96
100
  if (country && title) {
@@ -103,6 +107,7 @@ const getTitlesOther = (el) => {
103
107
  return null;
104
108
  }
105
109
  });
110
+ return titlesOther.filter((x) => x);
106
111
  };
107
112
  exports.getTitlesOther = getTitlesOther;
108
113
  const getPoster = (el) => {
@@ -8,4 +8,4 @@ export declare const getUrl: (el: HTMLElement) => string;
8
8
  export declare const getColorRating: (el: HTMLElement) => CSFDColorRating;
9
9
  export declare const getPoster: (el: HTMLElement) => string;
10
10
  export declare const getOrigins: (el: HTMLElement) => string[];
11
- export declare const parsePeople: (el: HTMLElement, type: 'directors' | 'actors') => CSFDCreator[];
11
+ export declare const parsePeople: (el: HTMLElement, type: "directors" | "actors") => CSFDCreator[];
@@ -30,9 +30,11 @@ const getPoster = (el) => {
30
30
  };
31
31
  exports.getPoster = getPoster;
32
32
  const getOrigins = (el) => {
33
- var _a;
34
- const originsRaw = el.querySelector('.article-content p .info').text;
35
- const originsAll = (_a = originsRaw === null || originsRaw === void 0 ? void 0 : originsRaw.split(', ')) === null || _a === void 0 ? void 0 : _a[0];
33
+ var _a, _b;
34
+ const originsRaw = (_a = el.querySelector('.article-content p .info')) === null || _a === void 0 ? void 0 : _a.text;
35
+ if (!originsRaw)
36
+ return [];
37
+ const originsAll = (_b = originsRaw === null || originsRaw === void 0 ? void 0 : originsRaw.split(', ')) === null || _b === void 0 ? void 0 : _b[0];
36
38
  return originsAll === null || originsAll === void 0 ? void 0 : originsAll.split('/').map((country) => country.trim());
37
39
  };
38
40
  exports.getOrigins = getOrigins;
@@ -23,7 +23,8 @@ const getTitle = (el) => {
23
23
  };
24
24
  exports.getTitle = getTitle;
25
25
  const getYear = (el) => {
26
- return +el.querySelectorAll('td.name .film-title-info .info')[0].text.slice(1, -1);
26
+ var _a;
27
+ return +((_a = el.querySelectorAll('td.name .film-title-info .info')[0]) === null || _a === void 0 ? void 0 : _a.text.slice(1, -1)) || null;
27
28
  };
28
29
  exports.getYear = getYear;
29
30
  const getColorRating = (el) => {
@@ -1,7 +1,9 @@
1
+ import { CSFDCinema, CSFDCinemaPeriod } from 'interfaces/cinema.interface';
1
2
  import { CSFDCreator } from './interfaces/creator.interface';
2
3
  import { CSFDMovie } from './interfaces/movie.interface';
3
4
  import { CSFDSearch } from './interfaces/search.interface';
4
5
  import { CSFDUserRatingConfig, CSFDUserRatings } from './interfaces/user-ratings.interface';
6
+ import { CinemaScraper } from './services/cinema.service';
5
7
  import { CreatorScraper } from './services/creator.service';
6
8
  import { MovieScraper } from './services/movie.service';
7
9
  import { SearchScraper } from './services/search.service';
@@ -11,10 +13,12 @@ export declare class Csfd {
11
13
  private movieService;
12
14
  private creatorService;
13
15
  private searchService;
14
- constructor(userRatingsService: UserRatingsScraper, movieService: MovieScraper, creatorService: CreatorScraper, searchService: SearchScraper);
16
+ private cinemaService;
17
+ constructor(userRatingsService: UserRatingsScraper, movieService: MovieScraper, creatorService: CreatorScraper, searchService: SearchScraper, cinemaService: CinemaScraper);
15
18
  userRatings(user: string | number, config?: CSFDUserRatingConfig): Promise<CSFDUserRatings[]>;
16
19
  movie(movie: number): Promise<CSFDMovie>;
17
20
  creator(creator: number): Promise<CSFDCreator>;
18
21
  search(text: string): Promise<CSFDSearch>;
22
+ cinema(district: number, period: CSFDCinemaPeriod): Promise<CSFDCinema[]>;
19
23
  }
20
24
  export declare const csfd: Csfd;