node-csfd-api 4.1.4 → 4.1.5
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/dto/global.d.mts +10 -10
- package/dto/global.d.ts +10 -10
- package/dto/movie.d.mts +6 -6
- package/dto/movie.d.ts +6 -6
- package/dto/user-ratings.d.mts +6 -6
- package/dto/user-ratings.d.ts +6 -6
- package/dto/user-reviews.d.mts +6 -6
- package/dto/user-reviews.d.ts +6 -6
- package/helpers/movie.helper.js +3 -3
- package/helpers/movie.helper.js.map +1 -1
- package/helpers/movie.helper.mjs +3 -3
- package/helpers/movie.helper.mjs.map +1 -1
- package/helpers/search.helper.js +1 -1
- package/helpers/search.helper.js.map +1 -1
- package/helpers/search.helper.mjs +1 -1
- package/helpers/search.helper.mjs.map +1 -1
- package/package.json +1 -1
- package/services/user-ratings.service.js +2 -2
- package/services/user-ratings.service.js.map +1 -1
- package/services/user-ratings.service.mjs +2 -2
- package/services/user-ratings.service.mjs.map +1 -1
- package/services/user-reviews.service.js +2 -2
- package/services/user-reviews.service.js.map +1 -1
- package/services/user-reviews.service.mjs +2 -2
- package/services/user-reviews.service.mjs.map +1 -1
package/dto/global.d.mts
CHANGED
|
@@ -6,16 +6,16 @@ interface CSFDScreening {
|
|
|
6
6
|
url: string;
|
|
7
7
|
type: CSFDFilmTypes;
|
|
8
8
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
* Overall aggregated rating. (On the web usually represented by colors).
|
|
10
|
+
*
|
|
11
|
+
* 'unknown': unknown (gray color)
|
|
12
|
+
*
|
|
13
|
+
* 'good': 70% – 100 % (red color)
|
|
14
|
+
*
|
|
15
|
+
* 'average': 30% - 69% (blue color)
|
|
16
|
+
*
|
|
17
|
+
* 'bad': 0% - 29% (black color)
|
|
18
|
+
*/
|
|
19
19
|
colorRating: CSFDColorRating;
|
|
20
20
|
}
|
|
21
21
|
type CSFDColorRating = 'bad' | 'average' | 'good' | 'unknown';
|
package/dto/global.d.ts
CHANGED
|
@@ -6,16 +6,16 @@ interface CSFDScreening {
|
|
|
6
6
|
url: string;
|
|
7
7
|
type: CSFDFilmTypes;
|
|
8
8
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
* Overall aggregated rating. (On the web usually represented by colors).
|
|
10
|
+
*
|
|
11
|
+
* 'unknown': unknown (gray color)
|
|
12
|
+
*
|
|
13
|
+
* 'good': 70% – 100 % (red color)
|
|
14
|
+
*
|
|
15
|
+
* 'average': 30% - 69% (blue color)
|
|
16
|
+
*
|
|
17
|
+
* 'bad': 0% - 29% (black color)
|
|
18
|
+
*/
|
|
19
19
|
colorRating: CSFDColorRating;
|
|
20
20
|
}
|
|
21
21
|
type CSFDColorRating = 'bad' | 'average' | 'good' | 'unknown';
|
package/dto/movie.d.mts
CHANGED
|
@@ -42,12 +42,12 @@ interface CSFDTitlesOther {
|
|
|
42
42
|
}
|
|
43
43
|
interface CSFDMovieCreator {
|
|
44
44
|
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
* CSFD person ID.
|
|
46
|
+
*
|
|
47
|
+
* You can always assemble url from ID like this:
|
|
48
|
+
*
|
|
49
|
+
* `https://www.csfd.cz/tvurce/${id}`
|
|
50
|
+
*/
|
|
51
51
|
id: number;
|
|
52
52
|
name: string;
|
|
53
53
|
url: string;
|
package/dto/movie.d.ts
CHANGED
|
@@ -42,12 +42,12 @@ interface CSFDTitlesOther {
|
|
|
42
42
|
}
|
|
43
43
|
interface CSFDMovieCreator {
|
|
44
44
|
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
* CSFD person ID.
|
|
46
|
+
*
|
|
47
|
+
* You can always assemble url from ID like this:
|
|
48
|
+
*
|
|
49
|
+
* `https://www.csfd.cz/tvurce/${id}`
|
|
50
|
+
*/
|
|
51
51
|
id: number;
|
|
52
52
|
name: string;
|
|
53
53
|
url: string;
|
package/dto/user-ratings.d.mts
CHANGED
|
@@ -9,16 +9,16 @@ interface CSFDUserRatingConfig {
|
|
|
9
9
|
includesOnly?: CSFDFilmTypes[];
|
|
10
10
|
excludes?: CSFDFilmTypes[];
|
|
11
11
|
/**
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
* Fetch all ratings. (Warning: Use it wisely. Can be detected and banned. Consider using it together with `allPagesDelay` attribute)
|
|
13
|
+
*/
|
|
14
14
|
allPages?: boolean;
|
|
15
15
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
* Delay on each page request. In milliseconds
|
|
17
|
+
*/
|
|
18
18
|
allPagesDelay?: number;
|
|
19
19
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
* Specific page number to fetch (e.g., 2 for second page)
|
|
21
|
+
*/
|
|
22
22
|
page?: number;
|
|
23
23
|
}
|
|
24
24
|
type CSFDColors = 'lightgrey' | 'blue' | 'red' | 'grey';
|
package/dto/user-ratings.d.ts
CHANGED
|
@@ -9,16 +9,16 @@ interface CSFDUserRatingConfig {
|
|
|
9
9
|
includesOnly?: CSFDFilmTypes[];
|
|
10
10
|
excludes?: CSFDFilmTypes[];
|
|
11
11
|
/**
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
* Fetch all ratings. (Warning: Use it wisely. Can be detected and banned. Consider using it together with `allPagesDelay` attribute)
|
|
13
|
+
*/
|
|
14
14
|
allPages?: boolean;
|
|
15
15
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
* Delay on each page request. In milliseconds
|
|
17
|
+
*/
|
|
18
18
|
allPagesDelay?: number;
|
|
19
19
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
* Specific page number to fetch (e.g., 2 for second page)
|
|
21
|
+
*/
|
|
22
22
|
page?: number;
|
|
23
23
|
}
|
|
24
24
|
type CSFDColors = 'lightgrey' | 'blue' | 'red' | 'grey';
|
package/dto/user-reviews.d.mts
CHANGED
|
@@ -11,16 +11,16 @@ interface CSFDUserReviewsConfig {
|
|
|
11
11
|
includesOnly?: CSFDFilmTypes[];
|
|
12
12
|
excludes?: CSFDFilmTypes[];
|
|
13
13
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
* Fetch all reviews. (Warning: Use it wisely. Can be detected and banned. Consider using it together with `allPagesDelay` attribute)
|
|
15
|
+
*/
|
|
16
16
|
allPages?: boolean;
|
|
17
17
|
/**
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
* Delay on each page request. In milliseconds
|
|
19
|
+
*/
|
|
20
20
|
allPagesDelay?: number;
|
|
21
21
|
/**
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* Specific page number to fetch (e.g., 2 for second page)
|
|
23
|
+
*/
|
|
24
24
|
page?: number;
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
package/dto/user-reviews.d.ts
CHANGED
|
@@ -11,16 +11,16 @@ interface CSFDUserReviewsConfig {
|
|
|
11
11
|
includesOnly?: CSFDFilmTypes[];
|
|
12
12
|
excludes?: CSFDFilmTypes[];
|
|
13
13
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
* Fetch all reviews. (Warning: Use it wisely. Can be detected and banned. Consider using it together with `allPagesDelay` attribute)
|
|
15
|
+
*/
|
|
16
16
|
allPages?: boolean;
|
|
17
17
|
/**
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
* Delay on each page request. In milliseconds
|
|
19
|
+
*/
|
|
20
20
|
allPagesDelay?: number;
|
|
21
21
|
/**
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* Specific page number to fetch (e.g., 2 for second page)
|
|
23
|
+
*/
|
|
24
24
|
page?: number;
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
package/helpers/movie.helper.js
CHANGED
|
@@ -105,9 +105,9 @@ const getMovieDuration = (jsonLdRaw, el) => {
|
|
|
105
105
|
const getMovieTitlesOther = (el) => {
|
|
106
106
|
const namesNode = el.querySelectorAll(".film-names li");
|
|
107
107
|
if (!namesNode.length) return [];
|
|
108
|
-
return namesNode.map((el
|
|
109
|
-
const country = el
|
|
110
|
-
const title = el
|
|
108
|
+
return namesNode.map((el) => {
|
|
109
|
+
const country = el.querySelector("img.flag").attributes.alt;
|
|
110
|
+
const title = el.textContent.trim().split("\n")[0];
|
|
111
111
|
if (country && title) return {
|
|
112
112
|
country,
|
|
113
113
|
title
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"movie.helper.js","names":["getColor","parseISO8601Duration","el","addProtocol","parseIdFromUrl"],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDPremiere,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService\n} from '../dto/movie';\nimport { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper';\n\n/**\n * Maps language-specific movie creator group labels.\n * @param language - The language code (e.g., 'en', 'cs')\n * @param key - The key of the creator group (e.g., 'directors', 'writers')\n * @returns The localized label for the creator group\n */\nexport const getLocalizedCreatorLabel = (\n language: string | undefined,\n key: 'directors' | 'writers' | 'cinematography' | 'music' | 'actors' | 'basedOn' | 'producers' | 'filmEditing' | 'costumeDesign' | 'productionDesign' | 'casting' | 'sound' | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const labels: Record<string, Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>> = {\n en: {\n directors: 'Directed by',\n writers: 'Screenplay',\n cinematography: 'Cinematography',\n music: 'Composer',\n actors: 'Cast',\n basedOn: 'Based on',\n producers: 'Produced by',\n filmEditing: 'Editing',\n costumeDesign: 'Costumes',\n productionDesign: 'Production design',\n casting: 'Casting',\n sound: 'Sound',\n makeup: 'Make-up'\n },\n cs: {\n directors: 'Režie',\n writers: 'Scénář',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrají',\n basedOn: 'Předloha',\n producers: 'Produkce',\n filmEditing: 'Střih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografie',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n },\n sk: {\n directors: 'Réžia',\n writers: 'Scenár',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrajú',\n basedOn: 'Predloha',\n producers: 'Produkcia',\n filmEditing: 'Strih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografia',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n }\n };\n\n const lang = language || 'cs'; // Default to Czech\n return (labels[lang] || labels['cs'])[key];\n};\n\nexport const getMovieId = (el: HTMLElement): number => {\n const url = el.querySelector('.tabs .tab-nav-list a').attributes.href;\n return parseIdFromUrl(url);\n};\n\nexport const getMovieTitle = (el: HTMLElement): string => {\n return el.querySelector('h1').innerText.split(`(`)[0].trim();\n};\n\nexport const getMovieGenres = (el: HTMLElement): CSFDGenres[] => {\n const genresRaw = el.querySelector('.genres').textContent;\n return genresRaw.split(' / ') as CSFDGenres[];\n};\n\nexport const getMovieOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.origin').textContent;\n const origins = originsRaw.split(',')[0];\n return origins.split(' / ');\n};\n\nexport const getMovieColorRating = (bodyClasses: string[]): CSFDColorRating => {\n return getColor(bodyClasses[1]);\n};\n\nexport const getMovieRating = (el: HTMLElement): number => {\n const ratingRaw = el.querySelector('.film-rating-average').textContent;\n const rating = ratingRaw?.replace(/%/g, '').trim();\n const ratingInt = parseInt(rating);\n\n if (Number.isInteger(ratingInt)) {\n return ratingInt;\n } else {\n return null;\n }\n};\n\nexport const getMovieRatingCount = (el: HTMLElement): number => {\n const ratingCountRaw = el.querySelector('.box-rating-container .counter')?.textContent;\n const ratingCount = +ratingCountRaw?.replace(/[(\\s)]/g, '');\n if (Number.isInteger(ratingCount)) {\n return ratingCount;\n } else {\n return null;\n }\n};\n\nexport const getMovieYear = (el: string): number => {\n try {\n const jsonLd = JSON.parse(el);\n return +jsonLd.dateCreated;\n } catch (error) {\n console.error('node-csfd-api: Error parsing JSON-LD', error);\n return null;\n }\n};\n\nexport const getMovieDuration = (jsonLdRaw: string, el: HTMLElement): number => {\n let duration = null;\n try {\n const jsonLd = JSON.parse(jsonLdRaw);\n duration = jsonLd.duration;\n return parseISO8601Duration(duration);\n } catch (error) {\n const origin = el.querySelector('.origin').innerText;\n const timeString = origin.split(',');\n if (timeString.length > 2) {\n // Get last time elelment\n const timeString2 = timeString.pop().trim();\n // Clean it\n const timeRaw = timeString2.split('(')[0].trim();\n // Split by minutes and hours\n const hoursMinsRaw = timeRaw.split('min')[0];\n const hoursMins = hoursMinsRaw.split('h');\n // Resolve hours + minutes format\n duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n }\n};\n\nexport const getMovieTitlesOther = (el: HTMLElement): CSFDTitlesOther[] => {\n const namesNode = el.querySelectorAll('.film-names li');\n\n if (!namesNode.length) {\n return [];\n }\n\n const titlesOther = namesNode.map((el) => {\n const country = el.querySelector('img.flag').attributes.alt;\n const title = el.textContent.trim().split('\\n')[0];\n\n if (country && title) {\n return {\n country,\n title\n };\n } else {\n return null;\n }\n });\n\n return titlesOther.filter((x) => x);\n};\n\nexport const getMoviePoster = (el: HTMLElement | null): string => {\n const poster = el.querySelector('.film-posters img');\n // Resolve empty image\n if (poster) {\n if (poster.classNames?.includes('empty-image')) {\n return null;\n } else {\n // Full sized image (not thumb)\n const imageThumb = poster.attributes.src.split('?')[0];\n const image = imageThumb.replace(/\\/w140\\//, '/w1080/');\n return addProtocol(image);\n }\n } else {\n return null;\n }\n};\n\nexport const getMovieRandomPhoto = (el: HTMLElement | null): string => {\n const imageNode = el.querySelector('.gallery-item picture img');\n const image = imageNode?.attributes?.src;\n if (image) {\n return image.replace(/\\/w663\\//, '/w1326/');\n } else {\n return null;\n }\n};\n\nexport const getMovieTrivia = (el: HTMLElement | null): string[] => {\n const triviaNodes = el.querySelectorAll('.article-trivia ul li');\n if (triviaNodes?.length) {\n return triviaNodes.map((node) => node.textContent.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n } else {\n return null;\n }\n};\n\nexport const getMovieDescriptions = (el: HTMLElement): string[] => {\n return el\n .querySelectorAll('.body--plots .plot-full p, .body--plots .plots .plots-item p')\n .map((movie) => movie.textContent?.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n};\n\nconst parseMoviePeople = (el: HTMLElement): CSFDMovieCreator[] => {\n const people = el.querySelectorAll('a');\n return (\n people\n // Filter out \"more\" links\n .filter((x) => x.classNames.length === 0)\n .map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n })\n );\n};\n\nexport const getMovieGroup = (el: HTMLElement, group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.filter((elem) => elem.textContent.trim().includes(group))[0];\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): string => {\n const type = el.querySelector('.film-header-name .type');\n return type?.innerText?.replace(/[{()}]/g, '') || 'film';\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttons = el.querySelectorAll('.box-buttons .button');\n const buttonsVod = buttons.filter((x) => !x.classNames.includes('button-social'));\n vods = buttonsVod.map((btn) => {\n return {\n title: btn.textContent.trim() as CSFDVodService,\n url: btn.attributes.href\n };\n });\n }\n return vods.length ? vods : [];\n};\n\n// Get box content\nconst getBoxContent = (el: HTMLElement, box: string): HTMLElement => {\n const headers = el.querySelectorAll('section.box .box-header');\n return headers.find((header) => header.querySelector('h3')?.textContent.trim().includes(box))\n ?.parentNode;\n};\n\nexport const getMovieBoxMovies = (el: HTMLElement, boxName: CSFDBoxContent): CSFDMovieListItem[] => {\n const movieListItem: CSFDMovieListItem[] = [];\n const box = getBoxContent(el, boxName);\n const movieTitleNodes = box?.querySelectorAll('.article-header .film-title-name');\n if (movieTitleNodes?.length) {\n for (const item of movieTitleNodes) {\n movieListItem.push({\n id: parseIdFromUrl(item.attributes.href),\n title: item.textContent.trim(),\n url: `https://www.csfd.cz${item.attributes.href}`\n });\n }\n }\n return movieListItem;\n};\n\nexport const getMoviePremieres = (el: HTMLElement): CSFDPremiere[] => {\n const premiereNodes = el.querySelectorAll('.box-premieres li');\n const premiere: CSFDPremiere[] = [];\n for (const premiereNode of premiereNodes) {\n const title = premiereNode.querySelector('p + span').attributes.title;\n\n if (title) {\n const [date, ...company] = title?.split(' ');\n\n premiere.push({\n country: premiereNode.querySelector('.flag')?.attributes.title || null,\n format: premiereNode.querySelector('p').textContent.trim()?.split(' od')[0],\n date,\n company: company.join(' ')\n });\n }\n }\n return premiere;\n};\n\nexport const getMovieTags = (el: HTMLElement): string[] => {\n const tagsRaw = el.querySelectorAll('.box-content a[href*=\"/tag/\"]');\n return tagsRaw.map((tag) => tag.textContent);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"movie.helper.js","names":["getColor","parseISO8601Duration","addProtocol","parseIdFromUrl"],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDPremiere,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService\n} from '../dto/movie';\nimport { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper';\n\n/**\n * Maps language-specific movie creator group labels.\n * @param language - The language code (e.g., 'en', 'cs')\n * @param key - The key of the creator group (e.g., 'directors', 'writers')\n * @returns The localized label for the creator group\n */\nexport const getLocalizedCreatorLabel = (\n language: string | undefined,\n key: 'directors' | 'writers' | 'cinematography' | 'music' | 'actors' | 'basedOn' | 'producers' | 'filmEditing' | 'costumeDesign' | 'productionDesign' | 'casting' | 'sound' | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const labels: Record<string, Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>> = {\n en: {\n directors: 'Directed by',\n writers: 'Screenplay',\n cinematography: 'Cinematography',\n music: 'Composer',\n actors: 'Cast',\n basedOn: 'Based on',\n producers: 'Produced by',\n filmEditing: 'Editing',\n costumeDesign: 'Costumes',\n productionDesign: 'Production design',\n casting: 'Casting',\n sound: 'Sound',\n makeup: 'Make-up'\n },\n cs: {\n directors: 'Režie',\n writers: 'Scénář',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrají',\n basedOn: 'Předloha',\n producers: 'Produkce',\n filmEditing: 'Střih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografie',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n },\n sk: {\n directors: 'Réžia',\n writers: 'Scenár',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrajú',\n basedOn: 'Predloha',\n producers: 'Produkcia',\n filmEditing: 'Strih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografia',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n }\n };\n\n const lang = language || 'cs'; // Default to Czech\n return (labels[lang] || labels['cs'])[key];\n};\n\nexport const getMovieId = (el: HTMLElement): number => {\n const url = el.querySelector('.tabs .tab-nav-list a').attributes.href;\n return parseIdFromUrl(url);\n};\n\nexport const getMovieTitle = (el: HTMLElement): string => {\n return el.querySelector('h1').innerText.split(`(`)[0].trim();\n};\n\nexport const getMovieGenres = (el: HTMLElement): CSFDGenres[] => {\n const genresRaw = el.querySelector('.genres').textContent;\n return genresRaw.split(' / ') as CSFDGenres[];\n};\n\nexport const getMovieOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.origin').textContent;\n const origins = originsRaw.split(',')[0];\n return origins.split(' / ');\n};\n\nexport const getMovieColorRating = (bodyClasses: string[]): CSFDColorRating => {\n return getColor(bodyClasses[1]);\n};\n\nexport const getMovieRating = (el: HTMLElement): number => {\n const ratingRaw = el.querySelector('.film-rating-average').textContent;\n const rating = ratingRaw?.replace(/%/g, '').trim();\n const ratingInt = parseInt(rating);\n\n if (Number.isInteger(ratingInt)) {\n return ratingInt;\n } else {\n return null;\n }\n};\n\nexport const getMovieRatingCount = (el: HTMLElement): number => {\n const ratingCountRaw = el.querySelector('.box-rating-container .counter')?.textContent;\n const ratingCount = +ratingCountRaw?.replace(/[(\\s)]/g, '');\n if (Number.isInteger(ratingCount)) {\n return ratingCount;\n } else {\n return null;\n }\n};\n\nexport const getMovieYear = (el: string): number => {\n try {\n const jsonLd = JSON.parse(el);\n return +jsonLd.dateCreated;\n } catch (error) {\n console.error('node-csfd-api: Error parsing JSON-LD', error);\n return null;\n }\n};\n\nexport const getMovieDuration = (jsonLdRaw: string, el: HTMLElement): number => {\n let duration = null;\n try {\n const jsonLd = JSON.parse(jsonLdRaw);\n duration = jsonLd.duration;\n return parseISO8601Duration(duration);\n } catch (error) {\n const origin = el.querySelector('.origin').innerText;\n const timeString = origin.split(',');\n if (timeString.length > 2) {\n // Get last time elelment\n const timeString2 = timeString.pop().trim();\n // Clean it\n const timeRaw = timeString2.split('(')[0].trim();\n // Split by minutes and hours\n const hoursMinsRaw = timeRaw.split('min')[0];\n const hoursMins = hoursMinsRaw.split('h');\n // Resolve hours + minutes format\n duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n }\n};\n\nexport const getMovieTitlesOther = (el: HTMLElement): CSFDTitlesOther[] => {\n const namesNode = el.querySelectorAll('.film-names li');\n\n if (!namesNode.length) {\n return [];\n }\n\n const titlesOther = namesNode.map((el) => {\n const country = el.querySelector('img.flag').attributes.alt;\n const title = el.textContent.trim().split('\\n')[0];\n\n if (country && title) {\n return {\n country,\n title\n };\n } else {\n return null;\n }\n });\n\n return titlesOther.filter((x) => x);\n};\n\nexport const getMoviePoster = (el: HTMLElement | null): string => {\n const poster = el.querySelector('.film-posters img');\n // Resolve empty image\n if (poster) {\n if (poster.classNames?.includes('empty-image')) {\n return null;\n } else {\n // Full sized image (not thumb)\n const imageThumb = poster.attributes.src.split('?')[0];\n const image = imageThumb.replace(/\\/w140\\//, '/w1080/');\n return addProtocol(image);\n }\n } else {\n return null;\n }\n};\n\nexport const getMovieRandomPhoto = (el: HTMLElement | null): string => {\n const imageNode = el.querySelector('.gallery-item picture img');\n const image = imageNode?.attributes?.src;\n if (image) {\n return image.replace(/\\/w663\\//, '/w1326/');\n } else {\n return null;\n }\n};\n\nexport const getMovieTrivia = (el: HTMLElement | null): string[] => {\n const triviaNodes = el.querySelectorAll('.article-trivia ul li');\n if (triviaNodes?.length) {\n return triviaNodes.map((node) => node.textContent.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n } else {\n return null;\n }\n};\n\nexport const getMovieDescriptions = (el: HTMLElement): string[] => {\n return el\n .querySelectorAll('.body--plots .plot-full p, .body--plots .plots .plots-item p')\n .map((movie) => movie.textContent?.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n};\n\nconst parseMoviePeople = (el: HTMLElement): CSFDMovieCreator[] => {\n const people = el.querySelectorAll('a');\n return (\n people\n // Filter out \"more\" links\n .filter((x) => x.classNames.length === 0)\n .map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n })\n );\n};\n\nexport const getMovieGroup = (el: HTMLElement, group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.filter((elem) => elem.textContent.trim().includes(group))[0];\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): string => {\n const type = el.querySelector('.film-header-name .type');\n return type?.innerText?.replace(/[{()}]/g, '') || 'film';\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttons = el.querySelectorAll('.box-buttons .button');\n const buttonsVod = buttons.filter((x) => !x.classNames.includes('button-social'));\n vods = buttonsVod.map((btn) => {\n return {\n title: btn.textContent.trim() as CSFDVodService,\n url: btn.attributes.href\n };\n });\n }\n return vods.length ? vods : [];\n};\n\n// Get box content\nconst getBoxContent = (el: HTMLElement, box: string): HTMLElement => {\n const headers = el.querySelectorAll('section.box .box-header');\n return headers.find((header) => header.querySelector('h3')?.textContent.trim().includes(box))\n ?.parentNode;\n};\n\nexport const getMovieBoxMovies = (el: HTMLElement, boxName: CSFDBoxContent): CSFDMovieListItem[] => {\n const movieListItem: CSFDMovieListItem[] = [];\n const box = getBoxContent(el, boxName);\n const movieTitleNodes = box?.querySelectorAll('.article-header .film-title-name');\n if (movieTitleNodes?.length) {\n for (const item of movieTitleNodes) {\n movieListItem.push({\n id: parseIdFromUrl(item.attributes.href),\n title: item.textContent.trim(),\n url: `https://www.csfd.cz${item.attributes.href}`\n });\n }\n }\n return movieListItem;\n};\n\nexport const getMoviePremieres = (el: HTMLElement): CSFDPremiere[] => {\n const premiereNodes = el.querySelectorAll('.box-premieres li');\n const premiere: CSFDPremiere[] = [];\n for (const premiereNode of premiereNodes) {\n const title = premiereNode.querySelector('p + span').attributes.title;\n\n if (title) {\n const [date, ...company] = title?.split(' ');\n\n premiere.push({\n country: premiereNode.querySelector('.flag')?.attributes.title || null,\n format: premiereNode.querySelector('p').textContent.trim()?.split(' od')[0],\n date,\n company: company.join(' ')\n });\n }\n }\n return premiere;\n};\n\nexport const getMovieTags = (el: HTMLElement): string[] => {\n const tagsRaw = el.querySelectorAll('.box-content a[href*=\"/tag/\"]');\n return tagsRaw.map((tag) => tag.textContent);\n};\n"],"mappings":"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"}
|
package/helpers/movie.helper.mjs
CHANGED
|
@@ -105,9 +105,9 @@ const getMovieDuration = (jsonLdRaw, el) => {
|
|
|
105
105
|
const getMovieTitlesOther = (el) => {
|
|
106
106
|
const namesNode = el.querySelectorAll(".film-names li");
|
|
107
107
|
if (!namesNode.length) return [];
|
|
108
|
-
return namesNode.map((el
|
|
109
|
-
const country = el
|
|
110
|
-
const title = el
|
|
108
|
+
return namesNode.map((el) => {
|
|
109
|
+
const country = el.querySelector("img.flag").attributes.alt;
|
|
110
|
+
const title = el.textContent.trim().split("\n")[0];
|
|
111
111
|
if (country && title) return {
|
|
112
112
|
country,
|
|
113
113
|
title
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"movie.helper.mjs","names":["el"],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDPremiere,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService\n} from '../dto/movie';\nimport { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper';\n\n/**\n * Maps language-specific movie creator group labels.\n * @param language - The language code (e.g., 'en', 'cs')\n * @param key - The key of the creator group (e.g., 'directors', 'writers')\n * @returns The localized label for the creator group\n */\nexport const getLocalizedCreatorLabel = (\n language: string | undefined,\n key: 'directors' | 'writers' | 'cinematography' | 'music' | 'actors' | 'basedOn' | 'producers' | 'filmEditing' | 'costumeDesign' | 'productionDesign' | 'casting' | 'sound' | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const labels: Record<string, Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>> = {\n en: {\n directors: 'Directed by',\n writers: 'Screenplay',\n cinematography: 'Cinematography',\n music: 'Composer',\n actors: 'Cast',\n basedOn: 'Based on',\n producers: 'Produced by',\n filmEditing: 'Editing',\n costumeDesign: 'Costumes',\n productionDesign: 'Production design',\n casting: 'Casting',\n sound: 'Sound',\n makeup: 'Make-up'\n },\n cs: {\n directors: 'Režie',\n writers: 'Scénář',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrají',\n basedOn: 'Předloha',\n producers: 'Produkce',\n filmEditing: 'Střih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografie',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n },\n sk: {\n directors: 'Réžia',\n writers: 'Scenár',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrajú',\n basedOn: 'Predloha',\n producers: 'Produkcia',\n filmEditing: 'Strih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografia',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n }\n };\n\n const lang = language || 'cs'; // Default to Czech\n return (labels[lang] || labels['cs'])[key];\n};\n\nexport const getMovieId = (el: HTMLElement): number => {\n const url = el.querySelector('.tabs .tab-nav-list a').attributes.href;\n return parseIdFromUrl(url);\n};\n\nexport const getMovieTitle = (el: HTMLElement): string => {\n return el.querySelector('h1').innerText.split(`(`)[0].trim();\n};\n\nexport const getMovieGenres = (el: HTMLElement): CSFDGenres[] => {\n const genresRaw = el.querySelector('.genres').textContent;\n return genresRaw.split(' / ') as CSFDGenres[];\n};\n\nexport const getMovieOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.origin').textContent;\n const origins = originsRaw.split(',')[0];\n return origins.split(' / ');\n};\n\nexport const getMovieColorRating = (bodyClasses: string[]): CSFDColorRating => {\n return getColor(bodyClasses[1]);\n};\n\nexport const getMovieRating = (el: HTMLElement): number => {\n const ratingRaw = el.querySelector('.film-rating-average').textContent;\n const rating = ratingRaw?.replace(/%/g, '').trim();\n const ratingInt = parseInt(rating);\n\n if (Number.isInteger(ratingInt)) {\n return ratingInt;\n } else {\n return null;\n }\n};\n\nexport const getMovieRatingCount = (el: HTMLElement): number => {\n const ratingCountRaw = el.querySelector('.box-rating-container .counter')?.textContent;\n const ratingCount = +ratingCountRaw?.replace(/[(\\s)]/g, '');\n if (Number.isInteger(ratingCount)) {\n return ratingCount;\n } else {\n return null;\n }\n};\n\nexport const getMovieYear = (el: string): number => {\n try {\n const jsonLd = JSON.parse(el);\n return +jsonLd.dateCreated;\n } catch (error) {\n console.error('node-csfd-api: Error parsing JSON-LD', error);\n return null;\n }\n};\n\nexport const getMovieDuration = (jsonLdRaw: string, el: HTMLElement): number => {\n let duration = null;\n try {\n const jsonLd = JSON.parse(jsonLdRaw);\n duration = jsonLd.duration;\n return parseISO8601Duration(duration);\n } catch (error) {\n const origin = el.querySelector('.origin').innerText;\n const timeString = origin.split(',');\n if (timeString.length > 2) {\n // Get last time elelment\n const timeString2 = timeString.pop().trim();\n // Clean it\n const timeRaw = timeString2.split('(')[0].trim();\n // Split by minutes and hours\n const hoursMinsRaw = timeRaw.split('min')[0];\n const hoursMins = hoursMinsRaw.split('h');\n // Resolve hours + minutes format\n duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n }\n};\n\nexport const getMovieTitlesOther = (el: HTMLElement): CSFDTitlesOther[] => {\n const namesNode = el.querySelectorAll('.film-names li');\n\n if (!namesNode.length) {\n return [];\n }\n\n const titlesOther = namesNode.map((el) => {\n const country = el.querySelector('img.flag').attributes.alt;\n const title = el.textContent.trim().split('\\n')[0];\n\n if (country && title) {\n return {\n country,\n title\n };\n } else {\n return null;\n }\n });\n\n return titlesOther.filter((x) => x);\n};\n\nexport const getMoviePoster = (el: HTMLElement | null): string => {\n const poster = el.querySelector('.film-posters img');\n // Resolve empty image\n if (poster) {\n if (poster.classNames?.includes('empty-image')) {\n return null;\n } else {\n // Full sized image (not thumb)\n const imageThumb = poster.attributes.src.split('?')[0];\n const image = imageThumb.replace(/\\/w140\\//, '/w1080/');\n return addProtocol(image);\n }\n } else {\n return null;\n }\n};\n\nexport const getMovieRandomPhoto = (el: HTMLElement | null): string => {\n const imageNode = el.querySelector('.gallery-item picture img');\n const image = imageNode?.attributes?.src;\n if (image) {\n return image.replace(/\\/w663\\//, '/w1326/');\n } else {\n return null;\n }\n};\n\nexport const getMovieTrivia = (el: HTMLElement | null): string[] => {\n const triviaNodes = el.querySelectorAll('.article-trivia ul li');\n if (triviaNodes?.length) {\n return triviaNodes.map((node) => node.textContent.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n } else {\n return null;\n }\n};\n\nexport const getMovieDescriptions = (el: HTMLElement): string[] => {\n return el\n .querySelectorAll('.body--plots .plot-full p, .body--plots .plots .plots-item p')\n .map((movie) => movie.textContent?.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n};\n\nconst parseMoviePeople = (el: HTMLElement): CSFDMovieCreator[] => {\n const people = el.querySelectorAll('a');\n return (\n people\n // Filter out \"more\" links\n .filter((x) => x.classNames.length === 0)\n .map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n })\n );\n};\n\nexport const getMovieGroup = (el: HTMLElement, group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.filter((elem) => elem.textContent.trim().includes(group))[0];\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): string => {\n const type = el.querySelector('.film-header-name .type');\n return type?.innerText?.replace(/[{()}]/g, '') || 'film';\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttons = el.querySelectorAll('.box-buttons .button');\n const buttonsVod = buttons.filter((x) => !x.classNames.includes('button-social'));\n vods = buttonsVod.map((btn) => {\n return {\n title: btn.textContent.trim() as CSFDVodService,\n url: btn.attributes.href\n };\n });\n }\n return vods.length ? vods : [];\n};\n\n// Get box content\nconst getBoxContent = (el: HTMLElement, box: string): HTMLElement => {\n const headers = el.querySelectorAll('section.box .box-header');\n return headers.find((header) => header.querySelector('h3')?.textContent.trim().includes(box))\n ?.parentNode;\n};\n\nexport const getMovieBoxMovies = (el: HTMLElement, boxName: CSFDBoxContent): CSFDMovieListItem[] => {\n const movieListItem: CSFDMovieListItem[] = [];\n const box = getBoxContent(el, boxName);\n const movieTitleNodes = box?.querySelectorAll('.article-header .film-title-name');\n if (movieTitleNodes?.length) {\n for (const item of movieTitleNodes) {\n movieListItem.push({\n id: parseIdFromUrl(item.attributes.href),\n title: item.textContent.trim(),\n url: `https://www.csfd.cz${item.attributes.href}`\n });\n }\n }\n return movieListItem;\n};\n\nexport const getMoviePremieres = (el: HTMLElement): CSFDPremiere[] => {\n const premiereNodes = el.querySelectorAll('.box-premieres li');\n const premiere: CSFDPremiere[] = [];\n for (const premiereNode of premiereNodes) {\n const title = premiereNode.querySelector('p + span').attributes.title;\n\n if (title) {\n const [date, ...company] = title?.split(' ');\n\n premiere.push({\n country: premiereNode.querySelector('.flag')?.attributes.title || null,\n format: premiereNode.querySelector('p').textContent.trim()?.split(' od')[0],\n date,\n company: company.join(' ')\n });\n }\n }\n return premiere;\n};\n\nexport const getMovieTags = (el: HTMLElement): string[] => {\n const tagsRaw = el.querySelectorAll('.box-content a[href*=\"/tag/\"]');\n return tagsRaw.map((tag) => tag.textContent);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"movie.helper.mjs","names":[],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDPremiere,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService\n} from '../dto/movie';\nimport { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper';\n\n/**\n * Maps language-specific movie creator group labels.\n * @param language - The language code (e.g., 'en', 'cs')\n * @param key - The key of the creator group (e.g., 'directors', 'writers')\n * @returns The localized label for the creator group\n */\nexport const getLocalizedCreatorLabel = (\n language: string | undefined,\n key: 'directors' | 'writers' | 'cinematography' | 'music' | 'actors' | 'basedOn' | 'producers' | 'filmEditing' | 'costumeDesign' | 'productionDesign' | 'casting' | 'sound' | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const labels: Record<string, Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>> = {\n en: {\n directors: 'Directed by',\n writers: 'Screenplay',\n cinematography: 'Cinematography',\n music: 'Composer',\n actors: 'Cast',\n basedOn: 'Based on',\n producers: 'Produced by',\n filmEditing: 'Editing',\n costumeDesign: 'Costumes',\n productionDesign: 'Production design',\n casting: 'Casting',\n sound: 'Sound',\n makeup: 'Make-up'\n },\n cs: {\n directors: 'Režie',\n writers: 'Scénář',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrají',\n basedOn: 'Předloha',\n producers: 'Produkce',\n filmEditing: 'Střih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografie',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n },\n sk: {\n directors: 'Réžia',\n writers: 'Scenár',\n cinematography: 'Kamera',\n music: 'Hudba',\n actors: 'Hrajú',\n basedOn: 'Predloha',\n producers: 'Produkcia',\n filmEditing: 'Strih',\n costumeDesign: 'Kostýmy',\n productionDesign: 'Scénografia',\n casting: 'Casting',\n sound: 'Zvuk',\n makeup: 'Masky'\n }\n };\n\n const lang = language || 'cs'; // Default to Czech\n return (labels[lang] || labels['cs'])[key];\n};\n\nexport const getMovieId = (el: HTMLElement): number => {\n const url = el.querySelector('.tabs .tab-nav-list a').attributes.href;\n return parseIdFromUrl(url);\n};\n\nexport const getMovieTitle = (el: HTMLElement): string => {\n return el.querySelector('h1').innerText.split(`(`)[0].trim();\n};\n\nexport const getMovieGenres = (el: HTMLElement): CSFDGenres[] => {\n const genresRaw = el.querySelector('.genres').textContent;\n return genresRaw.split(' / ') as CSFDGenres[];\n};\n\nexport const getMovieOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.origin').textContent;\n const origins = originsRaw.split(',')[0];\n return origins.split(' / ');\n};\n\nexport const getMovieColorRating = (bodyClasses: string[]): CSFDColorRating => {\n return getColor(bodyClasses[1]);\n};\n\nexport const getMovieRating = (el: HTMLElement): number => {\n const ratingRaw = el.querySelector('.film-rating-average').textContent;\n const rating = ratingRaw?.replace(/%/g, '').trim();\n const ratingInt = parseInt(rating);\n\n if (Number.isInteger(ratingInt)) {\n return ratingInt;\n } else {\n return null;\n }\n};\n\nexport const getMovieRatingCount = (el: HTMLElement): number => {\n const ratingCountRaw = el.querySelector('.box-rating-container .counter')?.textContent;\n const ratingCount = +ratingCountRaw?.replace(/[(\\s)]/g, '');\n if (Number.isInteger(ratingCount)) {\n return ratingCount;\n } else {\n return null;\n }\n};\n\nexport const getMovieYear = (el: string): number => {\n try {\n const jsonLd = JSON.parse(el);\n return +jsonLd.dateCreated;\n } catch (error) {\n console.error('node-csfd-api: Error parsing JSON-LD', error);\n return null;\n }\n};\n\nexport const getMovieDuration = (jsonLdRaw: string, el: HTMLElement): number => {\n let duration = null;\n try {\n const jsonLd = JSON.parse(jsonLdRaw);\n duration = jsonLd.duration;\n return parseISO8601Duration(duration);\n } catch (error) {\n const origin = el.querySelector('.origin').innerText;\n const timeString = origin.split(',');\n if (timeString.length > 2) {\n // Get last time elelment\n const timeString2 = timeString.pop().trim();\n // Clean it\n const timeRaw = timeString2.split('(')[0].trim();\n // Split by minutes and hours\n const hoursMinsRaw = timeRaw.split('min')[0];\n const hoursMins = hoursMinsRaw.split('h');\n // Resolve hours + minutes format\n duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n }\n};\n\nexport const getMovieTitlesOther = (el: HTMLElement): CSFDTitlesOther[] => {\n const namesNode = el.querySelectorAll('.film-names li');\n\n if (!namesNode.length) {\n return [];\n }\n\n const titlesOther = namesNode.map((el) => {\n const country = el.querySelector('img.flag').attributes.alt;\n const title = el.textContent.trim().split('\\n')[0];\n\n if (country && title) {\n return {\n country,\n title\n };\n } else {\n return null;\n }\n });\n\n return titlesOther.filter((x) => x);\n};\n\nexport const getMoviePoster = (el: HTMLElement | null): string => {\n const poster = el.querySelector('.film-posters img');\n // Resolve empty image\n if (poster) {\n if (poster.classNames?.includes('empty-image')) {\n return null;\n } else {\n // Full sized image (not thumb)\n const imageThumb = poster.attributes.src.split('?')[0];\n const image = imageThumb.replace(/\\/w140\\//, '/w1080/');\n return addProtocol(image);\n }\n } else {\n return null;\n }\n};\n\nexport const getMovieRandomPhoto = (el: HTMLElement | null): string => {\n const imageNode = el.querySelector('.gallery-item picture img');\n const image = imageNode?.attributes?.src;\n if (image) {\n return image.replace(/\\/w663\\//, '/w1326/');\n } else {\n return null;\n }\n};\n\nexport const getMovieTrivia = (el: HTMLElement | null): string[] => {\n const triviaNodes = el.querySelectorAll('.article-trivia ul li');\n if (triviaNodes?.length) {\n return triviaNodes.map((node) => node.textContent.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n } else {\n return null;\n }\n};\n\nexport const getMovieDescriptions = (el: HTMLElement): string[] => {\n return el\n .querySelectorAll('.body--plots .plot-full p, .body--plots .plots .plots-item p')\n .map((movie) => movie.textContent?.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm, ''));\n};\n\nconst parseMoviePeople = (el: HTMLElement): CSFDMovieCreator[] => {\n const people = el.querySelectorAll('a');\n return (\n people\n // Filter out \"more\" links\n .filter((x) => x.classNames.length === 0)\n .map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n })\n );\n};\n\nexport const getMovieGroup = (el: HTMLElement, group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.filter((elem) => elem.textContent.trim().includes(group))[0];\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): string => {\n const type = el.querySelector('.film-header-name .type');\n return type?.innerText?.replace(/[{()}]/g, '') || 'film';\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttons = el.querySelectorAll('.box-buttons .button');\n const buttonsVod = buttons.filter((x) => !x.classNames.includes('button-social'));\n vods = buttonsVod.map((btn) => {\n return {\n title: btn.textContent.trim() as CSFDVodService,\n url: btn.attributes.href\n };\n });\n }\n return vods.length ? vods : [];\n};\n\n// Get box content\nconst getBoxContent = (el: HTMLElement, box: string): HTMLElement => {\n const headers = el.querySelectorAll('section.box .box-header');\n return headers.find((header) => header.querySelector('h3')?.textContent.trim().includes(box))\n ?.parentNode;\n};\n\nexport const getMovieBoxMovies = (el: HTMLElement, boxName: CSFDBoxContent): CSFDMovieListItem[] => {\n const movieListItem: CSFDMovieListItem[] = [];\n const box = getBoxContent(el, boxName);\n const movieTitleNodes = box?.querySelectorAll('.article-header .film-title-name');\n if (movieTitleNodes?.length) {\n for (const item of movieTitleNodes) {\n movieListItem.push({\n id: parseIdFromUrl(item.attributes.href),\n title: item.textContent.trim(),\n url: `https://www.csfd.cz${item.attributes.href}`\n });\n }\n }\n return movieListItem;\n};\n\nexport const getMoviePremieres = (el: HTMLElement): CSFDPremiere[] => {\n const premiereNodes = el.querySelectorAll('.box-premieres li');\n const premiere: CSFDPremiere[] = [];\n for (const premiereNode of premiereNodes) {\n const title = premiereNode.querySelector('p + span').attributes.title;\n\n if (title) {\n const [date, ...company] = title?.split(' ');\n\n premiere.push({\n country: premiereNode.querySelector('.flag')?.attributes.title || null,\n format: premiereNode.querySelector('p').textContent.trim()?.split(' od')[0],\n date,\n company: company.join(' ')\n });\n }\n }\n return premiere;\n};\n\nexport const getMovieTags = (el: HTMLElement): string[] => {\n const tagsRaw = el.querySelectorAll('.box-content a[href*=\"/tag/\"]');\n return tagsRaw.map((tag) => tag.textContent);\n};\n"],"mappings":"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"}
|
package/helpers/search.helper.js
CHANGED
|
@@ -29,7 +29,7 @@ const parseSearchPeople = (el, type) => {
|
|
|
29
29
|
let who;
|
|
30
30
|
if (type === "directors") who = "Režie:";
|
|
31
31
|
if (type === "actors") who = "Hrají:";
|
|
32
|
-
const peopleNode = Array.from(el && el.querySelectorAll(".article-content p")).find((el
|
|
32
|
+
const peopleNode = Array.from(el && el.querySelectorAll(".article-content p")).find((el) => el.textContent.includes(who));
|
|
33
33
|
if (peopleNode) return Array.from(peopleNode.querySelectorAll("a")).map((person) => {
|
|
34
34
|
return {
|
|
35
35
|
id: require_global_helper.parseIdFromUrl(person.attributes.href),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.helper.js","names":["parseColor","addProtocol","
|
|
1
|
+
{"version":3,"file":"search.helper.js","names":["parseColor","addProtocol","parseIdFromUrl"],"sources":["../../src/helpers/search.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovieCreator } from '../dto/movie';\nimport { CSFDColors } from '../dto/user-ratings';\nimport { addProtocol, parseColor, parseIdFromUrl } from './global.helper';\n\ntype Creator = 'Režie:' | 'Hrají:';\n\nexport const getSearchType = (el: HTMLElement): CSFDFilmTypes => {\n const type = el.querySelectorAll('.film-title-info .info')[1];\n return (type?.innerText?.replace(/[{()}]/g, '')?.trim() || 'film') as CSFDFilmTypes;\n};\n\nexport const getSearchTitle = (el: HTMLElement): string => {\n return el.querySelector('.film-title-name').text;\n};\n\nexport const getSearchYear = (el: HTMLElement): number => {\n return +el.querySelectorAll('.film-title-info .info')[0]?.innerText.replace(/[{()}]/g, '');\n};\n\nexport const getSearchUrl = (el: HTMLElement): string => {\n return el.querySelector('.film-title-name').attributes.href;\n};\n\nexport const getSearchColorRating = (el: HTMLElement): CSFDColorRating => {\n return parseColor(\n el.querySelector('.article-header i.icon').classNames.split(' ').pop() as CSFDColors\n );\n};\n\nexport const getSearchPoster = (el: HTMLElement): string => {\n const image = el.querySelector('img').attributes.src;\n return addProtocol(image);\n};\n\nexport const getSearchOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.article-content p .info')?.text;\n if (!originsRaw) return [];\n const originsAll = originsRaw?.split(', ')?.[0];\n return originsAll?.split('/').map((country) => country.trim());\n};\n\nexport const parseSearchPeople = (el: HTMLElement, type: 'directors' | 'actors'): CSFDMovieCreator[] => {\n let who: Creator;\n if (type === 'directors') who = 'Režie:';\n if (type === 'actors') who = 'Hrají:';\n\n const peopleNode = Array.from(el && el.querySelectorAll('.article-content p')).find((el) =>\n el.textContent.includes(who)\n );\n\n if (peopleNode) {\n const people = Array.from(peopleNode.querySelectorAll('a')) as unknown as HTMLElement[];\n\n return people.map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n });\n } else {\n return [];\n }\n};\n"],"mappings":";;;AAQA,MAAa,iBAAiB,OAAmC;AAE/D,QADa,GAAG,iBAAiB,yBAAyB,CAAC,IAC7C,WAAW,QAAQ,WAAW,GAAG,EAAE,MAAM,IAAI;;AAG7D,MAAa,kBAAkB,OAA4B;AACzD,QAAO,GAAG,cAAc,mBAAmB,CAAC;;AAG9C,MAAa,iBAAiB,OAA4B;AACxD,QAAO,CAAC,GAAG,iBAAiB,yBAAyB,CAAC,IAAI,UAAU,QAAQ,WAAW,GAAG;;AAG5F,MAAa,gBAAgB,OAA4B;AACvD,QAAO,GAAG,cAAc,mBAAmB,CAAC,WAAW;;AAGzD,MAAa,wBAAwB,OAAqC;AACxE,QAAOA,iCACL,GAAG,cAAc,yBAAyB,CAAC,WAAW,MAAM,IAAI,CAAC,KAAK,CACvE;;AAGH,MAAa,mBAAmB,OAA4B;CAC1D,MAAM,QAAQ,GAAG,cAAc,MAAM,CAAC,WAAW;AACjD,QAAOC,kCAAY,MAAM;;AAG3B,MAAa,oBAAoB,OAA8B;CAC7D,MAAM,aAAa,GAAG,cAAc,2BAA2B,EAAE;AACjE,KAAI,CAAC,WAAY,QAAO,EAAE;AAE1B,SADmB,YAAY,MAAM,KAAK,GAAG,KAC1B,MAAM,IAAI,CAAC,KAAK,YAAY,QAAQ,MAAM,CAAC;;AAGhE,MAAa,qBAAqB,IAAiB,SAAqD;CACtG,IAAI;AACJ,KAAI,SAAS,YAAa,OAAM;AAChC,KAAI,SAAS,SAAU,OAAM;CAE7B,MAAM,aAAa,MAAM,KAAK,MAAM,GAAG,iBAAiB,qBAAqB,CAAC,CAAC,MAAM,OACnF,GAAG,YAAY,SAAS,IAAI,CAC7B;AAED,KAAI,WAGF,QAFe,MAAM,KAAK,WAAW,iBAAiB,IAAI,CAAC,CAE7C,KAAK,WAAW;AAC5B,SAAO;GACL,IAAIC,qCAAe,OAAO,WAAW,KAAK;GAC1C,MAAM,OAAO,UAAU,MAAM;GAC7B,KAAK,sBAAsB,OAAO,WAAW;GAC9C;GACD;KAEF,QAAO,EAAE"}
|
|
@@ -29,7 +29,7 @@ const parseSearchPeople = (el, type) => {
|
|
|
29
29
|
let who;
|
|
30
30
|
if (type === "directors") who = "Režie:";
|
|
31
31
|
if (type === "actors") who = "Hrají:";
|
|
32
|
-
const peopleNode = Array.from(el && el.querySelectorAll(".article-content p")).find((el
|
|
32
|
+
const peopleNode = Array.from(el && el.querySelectorAll(".article-content p")).find((el) => el.textContent.includes(who));
|
|
33
33
|
if (peopleNode) return Array.from(peopleNode.querySelectorAll("a")).map((person) => {
|
|
34
34
|
return {
|
|
35
35
|
id: parseIdFromUrl(person.attributes.href),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.helper.mjs","names":[
|
|
1
|
+
{"version":3,"file":"search.helper.mjs","names":[],"sources":["../../src/helpers/search.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovieCreator } from '../dto/movie';\nimport { CSFDColors } from '../dto/user-ratings';\nimport { addProtocol, parseColor, parseIdFromUrl } from './global.helper';\n\ntype Creator = 'Režie:' | 'Hrají:';\n\nexport const getSearchType = (el: HTMLElement): CSFDFilmTypes => {\n const type = el.querySelectorAll('.film-title-info .info')[1];\n return (type?.innerText?.replace(/[{()}]/g, '')?.trim() || 'film') as CSFDFilmTypes;\n};\n\nexport const getSearchTitle = (el: HTMLElement): string => {\n return el.querySelector('.film-title-name').text;\n};\n\nexport const getSearchYear = (el: HTMLElement): number => {\n return +el.querySelectorAll('.film-title-info .info')[0]?.innerText.replace(/[{()}]/g, '');\n};\n\nexport const getSearchUrl = (el: HTMLElement): string => {\n return el.querySelector('.film-title-name').attributes.href;\n};\n\nexport const getSearchColorRating = (el: HTMLElement): CSFDColorRating => {\n return parseColor(\n el.querySelector('.article-header i.icon').classNames.split(' ').pop() as CSFDColors\n );\n};\n\nexport const getSearchPoster = (el: HTMLElement): string => {\n const image = el.querySelector('img').attributes.src;\n return addProtocol(image);\n};\n\nexport const getSearchOrigins = (el: HTMLElement): string[] => {\n const originsRaw = el.querySelector('.article-content p .info')?.text;\n if (!originsRaw) return [];\n const originsAll = originsRaw?.split(', ')?.[0];\n return originsAll?.split('/').map((country) => country.trim());\n};\n\nexport const parseSearchPeople = (el: HTMLElement, type: 'directors' | 'actors'): CSFDMovieCreator[] => {\n let who: Creator;\n if (type === 'directors') who = 'Režie:';\n if (type === 'actors') who = 'Hrají:';\n\n const peopleNode = Array.from(el && el.querySelectorAll('.article-content p')).find((el) =>\n el.textContent.includes(who)\n );\n\n if (peopleNode) {\n const people = Array.from(peopleNode.querySelectorAll('a')) as unknown as HTMLElement[];\n\n return people.map((person) => {\n return {\n id: parseIdFromUrl(person.attributes.href),\n name: person.innerText.trim(),\n url: `https://www.csfd.cz${person.attributes.href}`\n };\n });\n } else {\n return [];\n }\n};\n"],"mappings":";;;AAQA,MAAa,iBAAiB,OAAmC;AAE/D,QADa,GAAG,iBAAiB,yBAAyB,CAAC,IAC7C,WAAW,QAAQ,WAAW,GAAG,EAAE,MAAM,IAAI;;AAG7D,MAAa,kBAAkB,OAA4B;AACzD,QAAO,GAAG,cAAc,mBAAmB,CAAC;;AAG9C,MAAa,iBAAiB,OAA4B;AACxD,QAAO,CAAC,GAAG,iBAAiB,yBAAyB,CAAC,IAAI,UAAU,QAAQ,WAAW,GAAG;;AAG5F,MAAa,gBAAgB,OAA4B;AACvD,QAAO,GAAG,cAAc,mBAAmB,CAAC,WAAW;;AAGzD,MAAa,wBAAwB,OAAqC;AACxE,QAAO,WACL,GAAG,cAAc,yBAAyB,CAAC,WAAW,MAAM,IAAI,CAAC,KAAK,CACvE;;AAGH,MAAa,mBAAmB,OAA4B;CAC1D,MAAM,QAAQ,GAAG,cAAc,MAAM,CAAC,WAAW;AACjD,QAAO,YAAY,MAAM;;AAG3B,MAAa,oBAAoB,OAA8B;CAC7D,MAAM,aAAa,GAAG,cAAc,2BAA2B,EAAE;AACjE,KAAI,CAAC,WAAY,QAAO,EAAE;AAE1B,SADmB,YAAY,MAAM,KAAK,GAAG,KAC1B,MAAM,IAAI,CAAC,KAAK,YAAY,QAAQ,MAAM,CAAC;;AAGhE,MAAa,qBAAqB,IAAiB,SAAqD;CACtG,IAAI;AACJ,KAAI,SAAS,YAAa,OAAM;AAChC,KAAI,SAAS,SAAU,OAAM;CAE7B,MAAM,aAAa,MAAM,KAAK,MAAM,GAAG,iBAAiB,qBAAqB,CAAC,CAAC,MAAM,OACnF,GAAG,YAAY,SAAS,IAAI,CAC7B;AAED,KAAI,WAGF,QAFe,MAAM,KAAK,WAAW,iBAAiB,IAAI,CAAC,CAE7C,KAAK,WAAW;AAC5B,SAAO;GACL,IAAI,eAAe,OAAO,WAAW,KAAK;GAC1C,MAAM,OAAO,UAAU,MAAM;GAC7B,KAAK,sBAAsB,OAAO,WAAW;GAC9C;GACD;KAEF,QAAO,EAAE"}
|
package/package.json
CHANGED
|
@@ -20,8 +20,8 @@ var UserRatingsScraper = class {
|
|
|
20
20
|
console.log("Fetching all pages", pages);
|
|
21
21
|
for (let i = 2; i <= pages; i++) {
|
|
22
22
|
console.log("Fetching page", i, "out of", pages, "...");
|
|
23
|
-
const movies
|
|
24
|
-
allMovies = [...allMovies, ...this.getPage(config, movies
|
|
23
|
+
const movies = (0, node_html_parser.parse)(await require_index.fetchPage(require_vars.userRatingsUrl(user, i, { language: options?.language }), { ...options?.request })).querySelectorAll(".box-user-rating .table-container tbody tr");
|
|
24
|
+
allMovies = [...allMovies, ...this.getPage(config, movies)];
|
|
25
25
|
if (config.allPagesDelay) await require_global_helper.sleep(config.allPagesDelay);
|
|
26
26
|
}
|
|
27
27
|
return allMovies;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-ratings.service.js","names":["userRatingsUrl","fetchPage","
|
|
1
|
+
{"version":3,"file":"user-ratings.service.js","names":["userRatingsUrl","fetchPage","sleep","getUserRatingType","getUserRatingId","getUserRatingTitle","getUserRatingYear","getUserRatingUrl","getUserRatingColorRating","getUserRatingDate","getUserRating"],"sources":["../../src/services/user-ratings.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDColorRating, CSFDStars } from '../dto/global';\nimport { CSFDUserRatingConfig, CSFDUserRatings } from '../dto/user-ratings';\nimport { fetchPage } from '../fetchers';\nimport { sleep } from '../helpers/global.helper';\nimport {\n getUserRating,\n getUserRatingColorRating,\n getUserRatingDate,\n getUserRatingId,\n getUserRatingTitle,\n getUserRatingType,\n getUserRatingUrl,\n getUserRatingYear\n} from '../helpers/user-ratings.helper';\nimport { CSFDOptions } from '../types';\nimport { userRatingsUrl } from '../vars';\n\nexport class UserRatingsScraper {\n public async userRatings(\n user: string | number,\n config?: CSFDUserRatingConfig,\n options?: CSFDOptions\n ): Promise<CSFDUserRatings[]> {\n let allMovies: CSFDUserRatings[] = [];\n const pageToFetch = config?.page || 1;\n const url = userRatingsUrl(user, pageToFetch > 1 ? pageToFetch : undefined, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('.box-user-rating .table-container tbody tr');\n\n // Get number of pages\n const pagesNode = items.querySelector('.pagination');\n const pages = +pagesNode?.childNodes[pagesNode.childNodes.length - 4].rawText || 1;\n\n allMovies = this.getPage(config, movies);\n\n if (config?.allPages) {\n console.log('User', user, url);\n console.log('Fetching all pages', pages);\n for (let i = 2; i <= pages; i++) {\n console.log('Fetching page', i, 'out of', pages, '...');\n const url = userRatingsUrl(user, i, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const items = parse(response);\n const movies = items.querySelectorAll('.box-user-rating .table-container tbody tr');\n allMovies = [...allMovies, ...this.getPage(config, movies)];\n\n // Sleep\n if (config.allPagesDelay) {\n await sleep(config.allPagesDelay);\n }\n }\n return allMovies;\n }\n\n return allMovies;\n }\n\n private getPage(config: CSFDUserRatingConfig, movies: HTMLElement[]) {\n const films: CSFDUserRatings[] = [];\n if (config) {\n if (config.includesOnly?.length && config.excludes?.length) {\n console.warn(\n `node-csfd-api:\n You can not use both parameters 'includesOnly' and 'excludes'.\n Parameter 'includesOnly' will be used now:`,\n config.includesOnly\n );\n }\n }\n\n for (const el of movies) {\n const type = getUserRatingType(el);\n\n // Filtering includesOnly\n if (config?.includesOnly?.length) {\n if (config.includesOnly.some((include) => type === include)) {\n films.push(this.buildUserRatings(el));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserRatings(el));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type: getUserRatingType(el),\n url: getUserRatingUrl(el),\n colorRating: getUserRatingColorRating(el) as CSFDColorRating,\n userDate: getUserRatingDate(el),\n userRating: getUserRating(el) as CSFDStars\n };\n }\n}\n"],"mappings":";;;;;;;AAkBA,IAAa,qBAAb,MAAgC;CAC9B,MAAa,YACX,MACA,QACA,SAC4B;EAC5B,IAAI,YAA+B,EAAE;EACrC,MAAM,cAAc,QAAQ,QAAQ;EACpC,MAAM,MAAMA,4BAAe,MAAM,cAAc,IAAI,cAAc,QAAW,EAAE,UAAU,SAAS,UAAU,CAAC;EAE5G,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6CAA6C;EAGnF,MAAM,YAAY,MAAM,cAAc,cAAc;EACpD,MAAM,QAAQ,CAAC,WAAW,WAAW,UAAU,WAAW,SAAS,GAAG,WAAW;AAEjF,cAAY,KAAK,QAAQ,QAAQ,OAAO;AAExC,MAAI,QAAQ,UAAU;AACpB,WAAQ,IAAI,QAAQ,MAAM,IAAI;AAC9B,WAAQ,IAAI,sBAAsB,MAAM;AACxC,QAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,YAAQ,IAAI,iBAAiB,GAAG,UAAU,OAAO,MAAM;IAKvD,MAAM,qCAHW,MAAMA,wBADXD,4BAAe,MAAM,GAAG,EAAE,UAAU,SAAS,UAAU,CAAC,EAC9B,EAAE,GAAG,SAAS,SAAS,CAAC,CAEjC,CACR,iBAAiB,6CAA6C;AACnF,gBAAY,CAAC,GAAG,WAAW,GAAG,KAAK,QAAQ,QAAQ,OAAO,CAAC;AAG3D,QAAI,OAAO,cACT,OAAME,4BAAM,OAAO,cAAc;;AAGrC,UAAO;;AAGT,SAAO;;CAGT,AAAQ,QAAQ,QAA8B,QAAuB;EACnE,MAAM,QAA2B,EAAE;AACnC,MAAI,QACF;OAAI,OAAO,cAAc,UAAU,OAAO,UAAU,OAClD,SAAQ,KACN;;qDAGA,OAAO,aACR;;AAIL,OAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,OAAOC,8CAAkB,GAAG;AAGlC,OAAI,QAAQ,cAAc,QACxB;QAAI,OAAO,aAAa,MAAM,YAAY,SAAS,QAAQ,CACzD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;cAG9B,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;SAIvC,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;;AAGzC,SAAO;;CAGT,AAAQ,iBAAiB,IAAkC;AACzD,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B,MAAMH,8CAAkB,GAAG;GAC3B,KAAKI,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,0CAAc,GAAG;GAC9B"}
|
|
@@ -20,8 +20,8 @@ var UserRatingsScraper = class {
|
|
|
20
20
|
console.log("Fetching all pages", pages);
|
|
21
21
|
for (let i = 2; i <= pages; i++) {
|
|
22
22
|
console.log("Fetching page", i, "out of", pages, "...");
|
|
23
|
-
const movies
|
|
24
|
-
allMovies = [...allMovies, ...this.getPage(config, movies
|
|
23
|
+
const movies = parse(await fetchPage(userRatingsUrl(user, i, { language: options?.language }), { ...options?.request })).querySelectorAll(".box-user-rating .table-container tbody tr");
|
|
24
|
+
allMovies = [...allMovies, ...this.getPage(config, movies)];
|
|
25
25
|
if (config.allPagesDelay) await sleep(config.allPagesDelay);
|
|
26
26
|
}
|
|
27
27
|
return allMovies;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-ratings.service.mjs","names":[
|
|
1
|
+
{"version":3,"file":"user-ratings.service.mjs","names":[],"sources":["../../src/services/user-ratings.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDColorRating, CSFDStars } from '../dto/global';\nimport { CSFDUserRatingConfig, CSFDUserRatings } from '../dto/user-ratings';\nimport { fetchPage } from '../fetchers';\nimport { sleep } from '../helpers/global.helper';\nimport {\n getUserRating,\n getUserRatingColorRating,\n getUserRatingDate,\n getUserRatingId,\n getUserRatingTitle,\n getUserRatingType,\n getUserRatingUrl,\n getUserRatingYear\n} from '../helpers/user-ratings.helper';\nimport { CSFDOptions } from '../types';\nimport { userRatingsUrl } from '../vars';\n\nexport class UserRatingsScraper {\n public async userRatings(\n user: string | number,\n config?: CSFDUserRatingConfig,\n options?: CSFDOptions\n ): Promise<CSFDUserRatings[]> {\n let allMovies: CSFDUserRatings[] = [];\n const pageToFetch = config?.page || 1;\n const url = userRatingsUrl(user, pageToFetch > 1 ? pageToFetch : undefined, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('.box-user-rating .table-container tbody tr');\n\n // Get number of pages\n const pagesNode = items.querySelector('.pagination');\n const pages = +pagesNode?.childNodes[pagesNode.childNodes.length - 4].rawText || 1;\n\n allMovies = this.getPage(config, movies);\n\n if (config?.allPages) {\n console.log('User', user, url);\n console.log('Fetching all pages', pages);\n for (let i = 2; i <= pages; i++) {\n console.log('Fetching page', i, 'out of', pages, '...');\n const url = userRatingsUrl(user, i, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const items = parse(response);\n const movies = items.querySelectorAll('.box-user-rating .table-container tbody tr');\n allMovies = [...allMovies, ...this.getPage(config, movies)];\n\n // Sleep\n if (config.allPagesDelay) {\n await sleep(config.allPagesDelay);\n }\n }\n return allMovies;\n }\n\n return allMovies;\n }\n\n private getPage(config: CSFDUserRatingConfig, movies: HTMLElement[]) {\n const films: CSFDUserRatings[] = [];\n if (config) {\n if (config.includesOnly?.length && config.excludes?.length) {\n console.warn(\n `node-csfd-api:\n You can not use both parameters 'includesOnly' and 'excludes'.\n Parameter 'includesOnly' will be used now:`,\n config.includesOnly\n );\n }\n }\n\n for (const el of movies) {\n const type = getUserRatingType(el);\n\n // Filtering includesOnly\n if (config?.includesOnly?.length) {\n if (config.includesOnly.some((include) => type === include)) {\n films.push(this.buildUserRatings(el));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserRatings(el));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type: getUserRatingType(el),\n url: getUserRatingUrl(el),\n colorRating: getUserRatingColorRating(el) as CSFDColorRating,\n userDate: getUserRatingDate(el),\n userRating: getUserRating(el) as CSFDStars\n };\n }\n}\n"],"mappings":";;;;;;;AAkBA,IAAa,qBAAb,MAAgC;CAC9B,MAAa,YACX,MACA,QACA,SAC4B;EAC5B,IAAI,YAA+B,EAAE;EACrC,MAAM,cAAc,QAAQ,QAAQ;EACpC,MAAM,MAAM,eAAe,MAAM,cAAc,IAAI,cAAc,QAAW,EAAE,UAAU,SAAS,UAAU,CAAC;EAE5G,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6CAA6C;EAGnF,MAAM,YAAY,MAAM,cAAc,cAAc;EACpD,MAAM,QAAQ,CAAC,WAAW,WAAW,UAAU,WAAW,SAAS,GAAG,WAAW;AAEjF,cAAY,KAAK,QAAQ,QAAQ,OAAO;AAExC,MAAI,QAAQ,UAAU;AACpB,WAAQ,IAAI,QAAQ,MAAM,IAAI;AAC9B,WAAQ,IAAI,sBAAsB,MAAM;AACxC,QAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,YAAQ,IAAI,iBAAiB,GAAG,UAAU,OAAO,MAAM;IAKvD,MAAM,SADQ,MAFG,MAAM,UADX,eAAe,MAAM,GAAG,EAAE,UAAU,SAAS,UAAU,CAAC,EAC9B,EAAE,GAAG,SAAS,SAAS,CAAC,CAEjC,CACR,iBAAiB,6CAA6C;AACnF,gBAAY,CAAC,GAAG,WAAW,GAAG,KAAK,QAAQ,QAAQ,OAAO,CAAC;AAG3D,QAAI,OAAO,cACT,OAAM,MAAM,OAAO,cAAc;;AAGrC,UAAO;;AAGT,SAAO;;CAGT,AAAQ,QAAQ,QAA8B,QAAuB;EACnE,MAAM,QAA2B,EAAE;AACnC,MAAI,QACF;OAAI,OAAO,cAAc,UAAU,OAAO,UAAU,OAClD,SAAQ,KACN;;qDAGA,OAAO,aACR;;AAIL,OAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,OAAO,kBAAkB,GAAG;AAGlC,OAAI,QAAQ,cAAc,QACxB;QAAI,OAAO,aAAa,MAAM,YAAY,SAAS,QAAQ,CACzD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;cAG9B,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;SAIvC,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;;AAGzC,SAAO;;CAGT,AAAQ,iBAAiB,IAAkC;AACzD,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B,MAAM,kBAAkB,GAAG;GAC3B,KAAK,iBAAiB,GAAG;GACzB,aAAa,yBAAyB,GAAG;GACzC,UAAU,kBAAkB,GAAG;GAC/B,YAAY,cAAc,GAAG;GAC9B"}
|
|
@@ -20,8 +20,8 @@ var UserReviewsScraper = class {
|
|
|
20
20
|
console.log("Fetching all pages", pages);
|
|
21
21
|
for (let i = 2; i <= pages; i++) {
|
|
22
22
|
console.log("Fetching page", i, "out of", pages, "...");
|
|
23
|
-
const reviews
|
|
24
|
-
allReviews = [...allReviews, ...this.getPage(config, reviews
|
|
23
|
+
const reviews = (0, node_html_parser.parse)(await require_index.fetchPage(require_vars.userReviewsUrl(user, i, { language: options?.language }), { ...options?.request })).querySelectorAll(".user-reviews .article");
|
|
24
|
+
allReviews = [...allReviews, ...this.getPage(config, reviews)];
|
|
25
25
|
if (config.allPagesDelay) await require_global_helper.sleep(config.allPagesDelay);
|
|
26
26
|
}
|
|
27
27
|
return allReviews;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-reviews.service.js","names":["userReviewsUrl","fetchPage","
|
|
1
|
+
{"version":3,"file":"user-reviews.service.js","names":["userReviewsUrl","fetchPage","sleep","getUserReviewType","getUserReviewId","getUserReviewTitle","getUserReviewYear","getUserReviewUrl","getUserReviewColorRating","getUserReviewDate","getUserReviewRating","getUserReviewText","getUserReviewPoster"],"sources":["../../src/services/user-reviews.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDColorRating, CSFDStars } from '../dto/global';\nimport { CSFDUserReviews, CSFDUserReviewsConfig } from '../dto/user-reviews';\nimport { fetchPage } from '../fetchers';\nimport { sleep } from '../helpers/global.helper';\nimport {\n getUserReviewColorRating,\n getUserReviewDate,\n getUserReviewId,\n getUserReviewPoster,\n getUserReviewRating,\n getUserReviewText,\n getUserReviewTitle,\n getUserReviewType,\n getUserReviewUrl,\n getUserReviewYear\n} from '../helpers/user-reviews.helper';\nimport { CSFDOptions } from '../types';\nimport { userReviewsUrl } from '../vars';\n\nexport class UserReviewsScraper {\n public async userReviews(\n user: string | number,\n config?: CSFDUserReviewsConfig,\n options?: CSFDOptions\n ): Promise<CSFDUserReviews[]> {\n let allReviews: CSFDUserReviews[] = [];\n const pageToFetch = config?.page || 1;\n const url = userReviewsUrl(user, pageToFetch > 1 ? pageToFetch : undefined, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-reviews .article');\n\n // Get number of pages\n const pagesNode = items.querySelector('.pagination');\n const pages = +pagesNode?.childNodes[pagesNode.childNodes.length - 4].rawText || 1;\n\n allReviews = this.getPage(config, reviews);\n\n if (config?.allPages) {\n console.log('User', user, url);\n console.log('Fetching all pages', pages);\n for (let i = 2; i <= pages; i++) {\n console.log('Fetching page', i, 'out of', pages, '...');\n const url = userReviewsUrl(user, i, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-reviews .article');\n allReviews = [...allReviews, ...this.getPage(config, reviews)];\n\n // Sleep\n if (config.allPagesDelay) {\n await sleep(config.allPagesDelay);\n }\n }\n return allReviews;\n }\n\n return allReviews;\n }\n\n private getPage(config: CSFDUserReviewsConfig, reviews: HTMLElement[]) {\n const films: CSFDUserReviews[] = [];\n if (config) {\n if (config.includesOnly?.length && config.excludes?.length) {\n console.warn(\n `node-csfd-api:\n You can not use both parameters 'includesOnly' and 'excludes'.\n Parameter 'includesOnly' will be used now:`,\n config.includesOnly\n );\n }\n }\n\n for (const el of reviews) {\n const type = getUserReviewType(el);\n\n // Filtering includesOnly\n if (config?.includesOnly?.length) {\n if (config.includesOnly.some((include) => type === include)) {\n films.push(this.buildUserReviews(el));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserReviews(el));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type: getUserReviewType(el),\n url: getUserReviewUrl(el),\n colorRating: getUserReviewColorRating(el) as CSFDColorRating,\n userDate: getUserReviewDate(el),\n userRating: getUserReviewRating(el) as CSFDStars,\n text: getUserReviewText(el),\n poster: getUserReviewPoster(el)\n };\n }\n}\n"],"mappings":";;;;;;;AAoBA,IAAa,qBAAb,MAAgC;CAC9B,MAAa,YACX,MACA,QACA,SAC4B;EAC5B,IAAI,aAAgC,EAAE;EACtC,MAAM,cAAc,QAAQ,QAAQ;EACpC,MAAM,MAAMA,4BAAe,MAAM,cAAc,IAAI,cAAc,QAAW,EAAE,UAAU,SAAS,UAAU,CAAC;EAE5G,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,yBAAyB;EAGhE,MAAM,YAAY,MAAM,cAAc,cAAc;EACpD,MAAM,QAAQ,CAAC,WAAW,WAAW,UAAU,WAAW,SAAS,GAAG,WAAW;AAEjF,eAAa,KAAK,QAAQ,QAAQ,QAAQ;AAE1C,MAAI,QAAQ,UAAU;AACpB,WAAQ,IAAI,QAAQ,MAAM,IAAI;AAC9B,WAAQ,IAAI,sBAAsB,MAAM;AACxC,QAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,YAAQ,IAAI,iBAAiB,GAAG,UAAU,OAAO,MAAM;IAKvD,MAAM,sCAHW,MAAMA,wBADXD,4BAAe,MAAM,GAAG,EAAE,UAAU,SAAS,UAAU,CAAC,EAC9B,EAAE,GAAG,SAAS,SAAS,CAAC,CAEjC,CACP,iBAAiB,yBAAyB;AAChE,iBAAa,CAAC,GAAG,YAAY,GAAG,KAAK,QAAQ,QAAQ,QAAQ,CAAC;AAG9D,QAAI,OAAO,cACT,OAAME,4BAAM,OAAO,cAAc;;AAGrC,UAAO;;AAGT,SAAO;;CAGT,AAAQ,QAAQ,QAA+B,SAAwB;EACrE,MAAM,QAA2B,EAAE;AACnC,MAAI,QACF;OAAI,OAAO,cAAc,UAAU,OAAO,UAAU,OAClD,SAAQ,KACN;;qDAGA,OAAO,aACR;;AAIL,OAAK,MAAM,MAAM,SAAS;GACxB,MAAM,OAAOC,8CAAkB,GAAG;AAGlC,OAAI,QAAQ,cAAc,QACxB;QAAI,OAAO,aAAa,MAAM,YAAY,SAAS,QAAQ,CACzD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;cAG9B,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;SAIvC,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;;AAGzC,SAAO;;CAGT,AAAQ,iBAAiB,IAAkC;AACzD,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B,MAAMH,8CAAkB,GAAG;GAC3B,KAAKI,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,gDAAoB,GAAG;GACnC,MAAMC,8CAAkB,GAAG;GAC3B,QAAQC,gDAAoB,GAAG;GAChC"}
|
|
@@ -20,8 +20,8 @@ var UserReviewsScraper = class {
|
|
|
20
20
|
console.log("Fetching all pages", pages);
|
|
21
21
|
for (let i = 2; i <= pages; i++) {
|
|
22
22
|
console.log("Fetching page", i, "out of", pages, "...");
|
|
23
|
-
const reviews
|
|
24
|
-
allReviews = [...allReviews, ...this.getPage(config, reviews
|
|
23
|
+
const reviews = parse(await fetchPage(userReviewsUrl(user, i, { language: options?.language }), { ...options?.request })).querySelectorAll(".user-reviews .article");
|
|
24
|
+
allReviews = [...allReviews, ...this.getPage(config, reviews)];
|
|
25
25
|
if (config.allPagesDelay) await sleep(config.allPagesDelay);
|
|
26
26
|
}
|
|
27
27
|
return allReviews;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-reviews.service.mjs","names":[
|
|
1
|
+
{"version":3,"file":"user-reviews.service.mjs","names":[],"sources":["../../src/services/user-reviews.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDColorRating, CSFDStars } from '../dto/global';\nimport { CSFDUserReviews, CSFDUserReviewsConfig } from '../dto/user-reviews';\nimport { fetchPage } from '../fetchers';\nimport { sleep } from '../helpers/global.helper';\nimport {\n getUserReviewColorRating,\n getUserReviewDate,\n getUserReviewId,\n getUserReviewPoster,\n getUserReviewRating,\n getUserReviewText,\n getUserReviewTitle,\n getUserReviewType,\n getUserReviewUrl,\n getUserReviewYear\n} from '../helpers/user-reviews.helper';\nimport { CSFDOptions } from '../types';\nimport { userReviewsUrl } from '../vars';\n\nexport class UserReviewsScraper {\n public async userReviews(\n user: string | number,\n config?: CSFDUserReviewsConfig,\n options?: CSFDOptions\n ): Promise<CSFDUserReviews[]> {\n let allReviews: CSFDUserReviews[] = [];\n const pageToFetch = config?.page || 1;\n const url = userReviewsUrl(user, pageToFetch > 1 ? pageToFetch : undefined, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-reviews .article');\n\n // Get number of pages\n const pagesNode = items.querySelector('.pagination');\n const pages = +pagesNode?.childNodes[pagesNode.childNodes.length - 4].rawText || 1;\n\n allReviews = this.getPage(config, reviews);\n\n if (config?.allPages) {\n console.log('User', user, url);\n console.log('Fetching all pages', pages);\n for (let i = 2; i <= pages; i++) {\n console.log('Fetching page', i, 'out of', pages, '...');\n const url = userReviewsUrl(user, i, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-reviews .article');\n allReviews = [...allReviews, ...this.getPage(config, reviews)];\n\n // Sleep\n if (config.allPagesDelay) {\n await sleep(config.allPagesDelay);\n }\n }\n return allReviews;\n }\n\n return allReviews;\n }\n\n private getPage(config: CSFDUserReviewsConfig, reviews: HTMLElement[]) {\n const films: CSFDUserReviews[] = [];\n if (config) {\n if (config.includesOnly?.length && config.excludes?.length) {\n console.warn(\n `node-csfd-api:\n You can not use both parameters 'includesOnly' and 'excludes'.\n Parameter 'includesOnly' will be used now:`,\n config.includesOnly\n );\n }\n }\n\n for (const el of reviews) {\n const type = getUserReviewType(el);\n\n // Filtering includesOnly\n if (config?.includesOnly?.length) {\n if (config.includesOnly.some((include) => type === include)) {\n films.push(this.buildUserReviews(el));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserReviews(el));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type: getUserReviewType(el),\n url: getUserReviewUrl(el),\n colorRating: getUserReviewColorRating(el) as CSFDColorRating,\n userDate: getUserReviewDate(el),\n userRating: getUserReviewRating(el) as CSFDStars,\n text: getUserReviewText(el),\n poster: getUserReviewPoster(el)\n };\n }\n}\n"],"mappings":";;;;;;;AAoBA,IAAa,qBAAb,MAAgC;CAC9B,MAAa,YACX,MACA,QACA,SAC4B;EAC5B,IAAI,aAAgC,EAAE;EACtC,MAAM,cAAc,QAAQ,QAAQ;EACpC,MAAM,MAAM,eAAe,MAAM,cAAc,IAAI,cAAc,QAAW,EAAE,UAAU,SAAS,UAAU,CAAC;EAE5G,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,yBAAyB;EAGhE,MAAM,YAAY,MAAM,cAAc,cAAc;EACpD,MAAM,QAAQ,CAAC,WAAW,WAAW,UAAU,WAAW,SAAS,GAAG,WAAW;AAEjF,eAAa,KAAK,QAAQ,QAAQ,QAAQ;AAE1C,MAAI,QAAQ,UAAU;AACpB,WAAQ,IAAI,QAAQ,MAAM,IAAI;AAC9B,WAAQ,IAAI,sBAAsB,MAAM;AACxC,QAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,YAAQ,IAAI,iBAAiB,GAAG,UAAU,OAAO,MAAM;IAKvD,MAAM,UADQ,MAFG,MAAM,UADX,eAAe,MAAM,GAAG,EAAE,UAAU,SAAS,UAAU,CAAC,EAC9B,EAAE,GAAG,SAAS,SAAS,CAAC,CAEjC,CACP,iBAAiB,yBAAyB;AAChE,iBAAa,CAAC,GAAG,YAAY,GAAG,KAAK,QAAQ,QAAQ,QAAQ,CAAC;AAG9D,QAAI,OAAO,cACT,OAAM,MAAM,OAAO,cAAc;;AAGrC,UAAO;;AAGT,SAAO;;CAGT,AAAQ,QAAQ,QAA+B,SAAwB;EACrE,MAAM,QAA2B,EAAE;AACnC,MAAI,QACF;OAAI,OAAO,cAAc,UAAU,OAAO,UAAU,OAClD,SAAQ,KACN;;qDAGA,OAAO,aACR;;AAIL,OAAK,MAAM,MAAM,SAAS;GACxB,MAAM,OAAO,kBAAkB,GAAG;AAGlC,OAAI,QAAQ,cAAc,QACxB;QAAI,OAAO,aAAa,MAAM,YAAY,SAAS,QAAQ,CACzD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;cAG9B,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;SAIvC,OAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC;;AAGzC,SAAO;;CAGT,AAAQ,iBAAiB,IAAkC;AACzD,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B,MAAM,kBAAkB,GAAG;GAC3B,KAAK,iBAAiB,GAAG;GACzB,aAAa,yBAAyB,GAAG;GACzC,UAAU,kBAAkB,GAAG;GAC/B,YAAY,oBAAoB,GAAG;GACnC,MAAM,kBAAkB,GAAG;GAC3B,QAAQ,oBAAoB,GAAG;GAChC"}
|