node-csfd-api 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -678,7 +678,7 @@ This library powers several production applications:
678
678
  - Related content (similar movies, trivia)
679
679
  - Alternative titles, premieres, tags
680
680
  - **Search**
681
- - Movies, TV series, and users
681
+ - Movies, TV series, Creators and users
682
682
  - **Creators**
683
683
  - Biography and filmography
684
684
  - **User Data**
@@ -687,9 +687,9 @@ This library powers several production applications:
687
687
 
688
688
  ### Planned Features 🚧
689
689
 
690
+ - [x] Search: Creator search functionality
690
691
  - [ ] Movie: reviews from movie detail page
691
692
  - [ ] Movie: Original soundtracks (OST) information
692
- - [ ] Search: Creator search functionality
693
693
  - [ ] Server: Caching layer for improved performance
694
694
  - [ ] Server: Rate limiting helpers
695
695
 
@@ -1 +1 @@
1
- {"version":3,"file":"movie.helper.js","names":["getColor","parseISO8601Duration","addProtocol","parseIdFromUrl","parseLastIdFromUrl","parseFilmType","parseDate"],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDCreators,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDParent,\n CSFDPremiere,\n CSFDSeriesChild,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService,\n MovieJsonLd\n} from '../dto/movie';\nimport { CSFDOptions } from '../types';\nimport {\n addProtocol,\n getColor,\n parseDate,\n parseFilmType,\n parseISO8601Duration,\n parseIdFromUrl,\n parseLastIdFromUrl\n} from './global.helper';\n\nconst CREATOR_LABELS: Record<\n string,\n Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>\n> = {\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/**\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:\n | 'directors'\n | 'writers'\n | 'cinematography'\n | 'music'\n | 'actors'\n | 'basedOn'\n | 'producers'\n | 'filmEditing'\n | 'costumeDesign'\n | 'productionDesign'\n | 'casting'\n | 'sound'\n | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const lang = language || 'cs'; // Default to Czech\n return (CREATOR_LABELS[lang] || CREATOR_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 getSeriesAndSeasonTitle = (\n el: HTMLElement\n): { seriesName: string | null; seasonName: string | null } => {\n const titleElement = el.querySelector('h1');\n if (!titleElement) {\n return { seriesName: null, seasonName: null };\n }\n\n const fullText = titleElement.innerText.trim();\n\n // Check if there's a series part indicated by ' - '\n if (fullText.includes(' - ')) {\n const [seriesName, seasonName] = fullText.split(' - ').map((part) => part.trim());\n return { seriesName, seasonName };\n }\n\n // If no series part found, return just the name\n return { seriesName: fullText, seasonName: null };\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 = (jsonLd: MovieJsonLd | null): number => {\n if (jsonLd && jsonLd.dateCreated) {\n return +jsonLd.dateCreated;\n }\n return null;\n};\n\nexport const getMovieDuration = (jsonLd: MovieJsonLd | null, el: HTMLElement): number => {\n if (jsonLd && jsonLd.duration) {\n try {\n return parseISO8601Duration(jsonLd.duration);\n } catch (e) {\n // ignore\n }\n }\n\n try {\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 const duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n } catch (error) {\n return null;\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\n// export 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 getMovieCreators = (el: HTMLElement, options?: CSFDOptions): CSFDCreators => {\n const creators: CSFDCreators = {\n directors: [],\n writers: [],\n cinematography: [],\n music: [],\n actors: [],\n basedOn: [],\n producers: [],\n filmEditing: [],\n costumeDesign: [],\n productionDesign: []\n };\n\n const groups = el.querySelectorAll('.creators h4');\n\n const keys = [\n 'directors',\n 'writers',\n 'cinematography',\n 'music',\n 'actors',\n 'basedOn',\n 'producers',\n 'filmEditing',\n 'costumeDesign',\n 'productionDesign'\n ] as const;\n\n const localizedLabels = keys.map((key) => ({\n key,\n label: getLocalizedCreatorLabel(options?.language, key) as string\n }));\n\n for (const group of groups) {\n const text = group.textContent.trim();\n for (const { key, label } of localizedLabels) {\n if (text.includes(label)) {\n if (group.parentNode) {\n creators[key] = parseMoviePeople(group.parentNode as HTMLElement);\n }\n break;\n }\n }\n }\n\n return creators;\n};\n\nexport const getSeasonsOrEpisodes = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDSeriesChild[] | null => {\n const childrenList = el.querySelector('.film-episodes-list');\n if (!childrenList) return null;\n\n const childrenNodes = childrenList.querySelectorAll('.film-title');\n if (!childrenNodes?.length) return [];\n\n return childrenNodes.map((season) => {\n const nameContainer = season.querySelector('.film-title-name');\n const infoContainer = season.querySelector('.info');\n\n const href = nameContainer?.getAttribute('href');\n const url = href ? (href.startsWith('/') ? `https://www.csfd.cz${href}` : href) : null;\n\n return {\n id: parseLastIdFromUrl(href || ''),\n title: nameContainer?.textContent?.trim() || null,\n url,\n info: infoContainer?.textContent?.replace(/[{()}]/g, '').trim() || null\n };\n });\n};\n\nexport const getEpisodeCode = (el: HTMLElement): string | null => {\n const filmHeaderName = el.querySelector('.film-header-name h1');\n if (!filmHeaderName) return null;\n\n const text = filmHeaderName.textContent?.trim() || '';\n const match = text.match(/\\(([^)]+)\\)/);\n const code = match ? match[1] : null;\n\n return code;\n};\n\nexport const detectSeasonOrEpisodeListType = (el: HTMLElement) => {\n const headerText = el.querySelector('.box-header h3')?.innerText.trim() ?? '';\n\n if (headerText.includes('Série')) return 'seasons';\n if (headerText.startsWith('Epizody')) return 'episodes';\n return null;\n};\n\nexport const getSeasonOrEpisodeParent = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDParent | null => {\n // Try h2 first (for episodes), then h1 (for seasons)\n let parents = el.querySelectorAll('.film-header h2 a');\n if (parents.length === 0) {\n parents = el.querySelectorAll('.film-header h1 a');\n }\n\n if (parents.length === 0) {\n if (!serie) return null;\n return { series: serie, season: null };\n }\n\n const [parentSeries, parentSeason] = parents;\n\n const seriesId = parseIdFromUrl(parentSeries?.getAttribute('href'));\n const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute('href') || '');\n const seriesTitle = parentSeries?.textContent?.trim() || null;\n const seasonTitle = parentSeason?.textContent?.trim() || null;\n\n const series = seriesId && seriesTitle ? { id: seriesId, title: seriesTitle } : null;\n const season = seasonId && seasonTitle ? { id: seasonId, title: seasonTitle } : null;\n\n if (!series && !season) return null;\n\n return { series, season };\n};\n\nexport const getMovieGroup = (\n el: HTMLElement,\n group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak\n): 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): CSFDFilmTypes => {\n const type = el.querySelector('.film-header-name .type');\n return parseFilmType(type?.innerText?.replace(/[{()}]/g, '') || 'film');\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttonsVod = el.querySelectorAll('.box-buttons-vod .vod-badge a');\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 = (\n el: HTMLElement,\n boxName: CSFDBoxContent\n): 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 [dateRaw, ...company] = title?.split(' ');\n const date = parseDate(dateRaw);\n\n if (date) {\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 }\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","parseLastIdFromUrl","parseFilmType","parseDate"],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDCreators,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDParent,\n CSFDPremiere,\n CSFDSeriesChild,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService,\n MovieJsonLd\n} from '../dto/movie';\nimport { CSFDOptions } from '../types';\nimport {\n addProtocol,\n getColor,\n parseDate,\n parseFilmType,\n parseISO8601Duration,\n parseIdFromUrl,\n parseLastIdFromUrl\n} from './global.helper';\n\nconst CREATOR_LABELS: Record<\n string,\n Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>\n> = {\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/**\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:\n | 'directors'\n | 'writers'\n | 'cinematography'\n | 'music'\n | 'actors'\n | 'basedOn'\n | 'producers'\n | 'filmEditing'\n | 'costumeDesign'\n | 'productionDesign'\n | 'casting'\n | 'sound'\n | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const lang = language || 'cs'; // Default to Czech\n return (CREATOR_LABELS[lang] || CREATOR_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 getSeriesAndSeasonTitle = (\n el: HTMLElement\n): { seriesName: string | null; seasonName: string | null } => {\n const titleElement = el.querySelector('h1');\n if (!titleElement) {\n return { seriesName: null, seasonName: null };\n }\n\n const fullText = titleElement.innerText.trim();\n\n // Check if there's a series part indicated by ' - '\n if (fullText.includes(' - ')) {\n const [seriesName, seasonName] = fullText.split(' - ').map((part) => part.trim());\n return { seriesName, seasonName };\n }\n\n // If no series part found, return just the name\n return { seriesName: fullText, seasonName: null };\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 = (jsonLd: MovieJsonLd | null): number => {\n if (jsonLd && jsonLd.dateCreated) {\n return +jsonLd.dateCreated;\n }\n return null;\n};\n\nexport const getMovieDuration = (jsonLd: MovieJsonLd | null, el: HTMLElement): number => {\n if (jsonLd && jsonLd.duration) {\n try {\n return parseISO8601Duration(jsonLd.duration);\n } catch (e) {\n // ignore\n }\n }\n\n try {\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 const duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n } catch (error) {\n return null;\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\n// export 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 getMovieCreators = (el: HTMLElement, options?: CSFDOptions): CSFDCreators => {\n const creators: CSFDCreators = {\n directors: [],\n writers: [],\n cinematography: [],\n music: [],\n actors: [],\n basedOn: [],\n producers: [],\n filmEditing: [],\n costumeDesign: [],\n productionDesign: []\n };\n\n const groups = el.querySelectorAll('.creators h4');\n\n const keys = [\n 'directors',\n 'writers',\n 'cinematography',\n 'music',\n 'actors',\n 'basedOn',\n 'producers',\n 'filmEditing',\n 'costumeDesign',\n 'productionDesign'\n ] as const;\n\n const localizedLabels = keys.map((key) => ({\n key,\n label: getLocalizedCreatorLabel(options?.language, key) as string\n }));\n\n for (const group of groups) {\n const text = group.textContent.trim();\n for (const { key, label } of localizedLabels) {\n if (text.includes(label)) {\n if (group.parentNode) {\n creators[key] = parseMoviePeople(group.parentNode as HTMLElement);\n }\n break;\n }\n }\n }\n\n return creators;\n};\n\nexport const getSeasonsOrEpisodes = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDSeriesChild[] | null => {\n const childrenList = el.querySelector('.film-episodes-list');\n if (!childrenList) return null;\n\n const childrenNodes = childrenList.querySelectorAll('.film-title');\n if (!childrenNodes?.length) return [];\n\n return childrenNodes.map((season) => {\n const nameContainer = season.querySelector('.film-title-name');\n const infoContainer = season.querySelector('.info');\n\n const href = nameContainer?.getAttribute('href');\n const url = href ? (href.startsWith('/') ? `https://www.csfd.cz${href}` : href) : null;\n\n return {\n id: parseLastIdFromUrl(href || ''),\n title: nameContainer?.textContent?.trim() || null,\n url,\n info: infoContainer?.textContent?.replace(/[{()}]/g, '').trim() || null\n };\n });\n};\n\nexport const getEpisodeCode = (el: HTMLElement): string | null => {\n const filmHeaderName = el.querySelector('.film-header-name h1');\n if (!filmHeaderName) return null;\n\n const text = filmHeaderName.textContent?.trim() || '';\n const match = text.match(/\\(([^)]+)\\)/);\n const code = match ? match[1] : null;\n\n return code;\n};\n\nexport const detectSeasonOrEpisodeListType = (el: HTMLElement) => {\n const headerText = el.querySelector('.box-header h3')?.innerText.trim() ?? '';\n\n if (headerText.includes('Série')) return 'seasons';\n if (headerText.startsWith('Epizody')) return 'episodes';\n return null;\n};\n\nexport const getSeasonOrEpisodeParent = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDParent | null => {\n // Try h2 first (for episodes), then h1 (for seasons)\n let parents = el.querySelectorAll('.film-header h2 a');\n if (parents.length === 0) {\n parents = el.querySelectorAll('.film-header h1 a');\n }\n\n if (parents.length === 0) {\n if (!serie) return null;\n return { series: serie, season: null };\n }\n\n const [parentSeries, parentSeason] = parents;\n\n const seriesId = parseIdFromUrl(parentSeries?.getAttribute('href'));\n const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute('href') || '');\n const seriesTitle = parentSeries?.textContent?.trim() || null;\n const seasonTitle = parentSeason?.textContent?.trim() || null;\n\n const series = seriesId && seriesTitle ? { id: seriesId, title: seriesTitle } : null;\n const season = seasonId && seasonTitle ? { id: seasonId, title: seasonTitle } : null;\n\n if (!series && !season) return null;\n\n return { series, season };\n};\n\nexport const getMovieGroup = (\n el: HTMLElement,\n group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak\n): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.find((elem) => elem.textContent.trim().includes(group as string));\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): CSFDFilmTypes => {\n const type = el.querySelector('.film-header-name .type');\n return parseFilmType(type?.innerText?.replace(/[{()}]/g, '') || 'film');\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttonsVod = el.querySelectorAll('.box-buttons-vod .vod-badge a');\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 = (\n el: HTMLElement,\n boxName: CSFDBoxContent\n): 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 [dateRaw, ...company] = title?.split(' ');\n const date = parseDate(dateRaw);\n\n if (date) {\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 }\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 +1 @@
1
- {"version":3,"file":"movie.helper.mjs","names":[],"sources":["../../src/helpers/movie.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDCreators,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDParent,\n CSFDPremiere,\n CSFDSeriesChild,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService,\n MovieJsonLd\n} from '../dto/movie';\nimport { CSFDOptions } from '../types';\nimport {\n addProtocol,\n getColor,\n parseDate,\n parseFilmType,\n parseISO8601Duration,\n parseIdFromUrl,\n parseLastIdFromUrl\n} from './global.helper';\n\nconst CREATOR_LABELS: Record<\n string,\n Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>\n> = {\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/**\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:\n | 'directors'\n | 'writers'\n | 'cinematography'\n | 'music'\n | 'actors'\n | 'basedOn'\n | 'producers'\n | 'filmEditing'\n | 'costumeDesign'\n | 'productionDesign'\n | 'casting'\n | 'sound'\n | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const lang = language || 'cs'; // Default to Czech\n return (CREATOR_LABELS[lang] || CREATOR_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 getSeriesAndSeasonTitle = (\n el: HTMLElement\n): { seriesName: string | null; seasonName: string | null } => {\n const titleElement = el.querySelector('h1');\n if (!titleElement) {\n return { seriesName: null, seasonName: null };\n }\n\n const fullText = titleElement.innerText.trim();\n\n // Check if there's a series part indicated by ' - '\n if (fullText.includes(' - ')) {\n const [seriesName, seasonName] = fullText.split(' - ').map((part) => part.trim());\n return { seriesName, seasonName };\n }\n\n // If no series part found, return just the name\n return { seriesName: fullText, seasonName: null };\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 = (jsonLd: MovieJsonLd | null): number => {\n if (jsonLd && jsonLd.dateCreated) {\n return +jsonLd.dateCreated;\n }\n return null;\n};\n\nexport const getMovieDuration = (jsonLd: MovieJsonLd | null, el: HTMLElement): number => {\n if (jsonLd && jsonLd.duration) {\n try {\n return parseISO8601Duration(jsonLd.duration);\n } catch (e) {\n // ignore\n }\n }\n\n try {\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 const duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n } catch (error) {\n return null;\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\n// export 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 getMovieCreators = (el: HTMLElement, options?: CSFDOptions): CSFDCreators => {\n const creators: CSFDCreators = {\n directors: [],\n writers: [],\n cinematography: [],\n music: [],\n actors: [],\n basedOn: [],\n producers: [],\n filmEditing: [],\n costumeDesign: [],\n productionDesign: []\n };\n\n const groups = el.querySelectorAll('.creators h4');\n\n const keys = [\n 'directors',\n 'writers',\n 'cinematography',\n 'music',\n 'actors',\n 'basedOn',\n 'producers',\n 'filmEditing',\n 'costumeDesign',\n 'productionDesign'\n ] as const;\n\n const localizedLabels = keys.map((key) => ({\n key,\n label: getLocalizedCreatorLabel(options?.language, key) as string\n }));\n\n for (const group of groups) {\n const text = group.textContent.trim();\n for (const { key, label } of localizedLabels) {\n if (text.includes(label)) {\n if (group.parentNode) {\n creators[key] = parseMoviePeople(group.parentNode as HTMLElement);\n }\n break;\n }\n }\n }\n\n return creators;\n};\n\nexport const getSeasonsOrEpisodes = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDSeriesChild[] | null => {\n const childrenList = el.querySelector('.film-episodes-list');\n if (!childrenList) return null;\n\n const childrenNodes = childrenList.querySelectorAll('.film-title');\n if (!childrenNodes?.length) return [];\n\n return childrenNodes.map((season) => {\n const nameContainer = season.querySelector('.film-title-name');\n const infoContainer = season.querySelector('.info');\n\n const href = nameContainer?.getAttribute('href');\n const url = href ? (href.startsWith('/') ? `https://www.csfd.cz${href}` : href) : null;\n\n return {\n id: parseLastIdFromUrl(href || ''),\n title: nameContainer?.textContent?.trim() || null,\n url,\n info: infoContainer?.textContent?.replace(/[{()}]/g, '').trim() || null\n };\n });\n};\n\nexport const getEpisodeCode = (el: HTMLElement): string | null => {\n const filmHeaderName = el.querySelector('.film-header-name h1');\n if (!filmHeaderName) return null;\n\n const text = filmHeaderName.textContent?.trim() || '';\n const match = text.match(/\\(([^)]+)\\)/);\n const code = match ? match[1] : null;\n\n return code;\n};\n\nexport const detectSeasonOrEpisodeListType = (el: HTMLElement) => {\n const headerText = el.querySelector('.box-header h3')?.innerText.trim() ?? '';\n\n if (headerText.includes('Série')) return 'seasons';\n if (headerText.startsWith('Epizody')) return 'episodes';\n return null;\n};\n\nexport const getSeasonOrEpisodeParent = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDParent | null => {\n // Try h2 first (for episodes), then h1 (for seasons)\n let parents = el.querySelectorAll('.film-header h2 a');\n if (parents.length === 0) {\n parents = el.querySelectorAll('.film-header h1 a');\n }\n\n if (parents.length === 0) {\n if (!serie) return null;\n return { series: serie, season: null };\n }\n\n const [parentSeries, parentSeason] = parents;\n\n const seriesId = parseIdFromUrl(parentSeries?.getAttribute('href'));\n const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute('href') || '');\n const seriesTitle = parentSeries?.textContent?.trim() || null;\n const seasonTitle = parentSeason?.textContent?.trim() || null;\n\n const series = seriesId && seriesTitle ? { id: seriesId, title: seriesTitle } : null;\n const season = seasonId && seasonTitle ? { id: seasonId, title: seasonTitle } : null;\n\n if (!series && !season) return null;\n\n return { series, season };\n};\n\nexport const getMovieGroup = (\n el: HTMLElement,\n group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak\n): 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): CSFDFilmTypes => {\n const type = el.querySelector('.film-header-name .type');\n return parseFilmType(type?.innerText?.replace(/[{()}]/g, '') || 'film');\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttonsVod = el.querySelectorAll('.box-buttons-vod .vod-badge a');\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 = (\n el: HTMLElement,\n boxName: CSFDBoxContent\n): 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 [dateRaw, ...company] = title?.split(' ');\n const date = parseDate(dateRaw);\n\n if (date) {\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 }\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, CSFDFilmTypes } from '../dto/global';\nimport {\n CSFDBoxContent,\n CSFDCreatorGroups,\n CSFDCreatorGroupsEnglish,\n CSFDCreatorGroupsSlovak,\n CSFDCreators,\n CSFDGenres,\n CSFDMovieCreator,\n CSFDMovieListItem,\n CSFDParent,\n CSFDPremiere,\n CSFDSeriesChild,\n CSFDTitlesOther,\n CSFDVod,\n CSFDVodService,\n MovieJsonLd\n} from '../dto/movie';\nimport { CSFDOptions } from '../types';\nimport {\n addProtocol,\n getColor,\n parseDate,\n parseFilmType,\n parseISO8601Duration,\n parseIdFromUrl,\n parseLastIdFromUrl\n} from './global.helper';\n\nconst CREATOR_LABELS: Record<\n string,\n Record<string, CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak>\n> = {\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/**\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:\n | 'directors'\n | 'writers'\n | 'cinematography'\n | 'music'\n | 'actors'\n | 'basedOn'\n | 'producers'\n | 'filmEditing'\n | 'costumeDesign'\n | 'productionDesign'\n | 'casting'\n | 'sound'\n | 'makeup'\n): CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak => {\n const lang = language || 'cs'; // Default to Czech\n return (CREATOR_LABELS[lang] || CREATOR_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 getSeriesAndSeasonTitle = (\n el: HTMLElement\n): { seriesName: string | null; seasonName: string | null } => {\n const titleElement = el.querySelector('h1');\n if (!titleElement) {\n return { seriesName: null, seasonName: null };\n }\n\n const fullText = titleElement.innerText.trim();\n\n // Check if there's a series part indicated by ' - '\n if (fullText.includes(' - ')) {\n const [seriesName, seasonName] = fullText.split(' - ').map((part) => part.trim());\n return { seriesName, seasonName };\n }\n\n // If no series part found, return just the name\n return { seriesName: fullText, seasonName: null };\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 = (jsonLd: MovieJsonLd | null): number => {\n if (jsonLd && jsonLd.dateCreated) {\n return +jsonLd.dateCreated;\n }\n return null;\n};\n\nexport const getMovieDuration = (jsonLd: MovieJsonLd | null, el: HTMLElement): number => {\n if (jsonLd && jsonLd.duration) {\n try {\n return parseISO8601Duration(jsonLd.duration);\n } catch (e) {\n // ignore\n }\n }\n\n try {\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 const duration = hoursMins.length > 1 ? +hoursMins[0] * 60 + +hoursMins[1] : +hoursMins[0];\n return duration;\n } else {\n return null;\n }\n } catch (error) {\n return null;\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\n// export 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 getMovieCreators = (el: HTMLElement, options?: CSFDOptions): CSFDCreators => {\n const creators: CSFDCreators = {\n directors: [],\n writers: [],\n cinematography: [],\n music: [],\n actors: [],\n basedOn: [],\n producers: [],\n filmEditing: [],\n costumeDesign: [],\n productionDesign: []\n };\n\n const groups = el.querySelectorAll('.creators h4');\n\n const keys = [\n 'directors',\n 'writers',\n 'cinematography',\n 'music',\n 'actors',\n 'basedOn',\n 'producers',\n 'filmEditing',\n 'costumeDesign',\n 'productionDesign'\n ] as const;\n\n const localizedLabels = keys.map((key) => ({\n key,\n label: getLocalizedCreatorLabel(options?.language, key) as string\n }));\n\n for (const group of groups) {\n const text = group.textContent.trim();\n for (const { key, label } of localizedLabels) {\n if (text.includes(label)) {\n if (group.parentNode) {\n creators[key] = parseMoviePeople(group.parentNode as HTMLElement);\n }\n break;\n }\n }\n }\n\n return creators;\n};\n\nexport const getSeasonsOrEpisodes = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDSeriesChild[] | null => {\n const childrenList = el.querySelector('.film-episodes-list');\n if (!childrenList) return null;\n\n const childrenNodes = childrenList.querySelectorAll('.film-title');\n if (!childrenNodes?.length) return [];\n\n return childrenNodes.map((season) => {\n const nameContainer = season.querySelector('.film-title-name');\n const infoContainer = season.querySelector('.info');\n\n const href = nameContainer?.getAttribute('href');\n const url = href ? (href.startsWith('/') ? `https://www.csfd.cz${href}` : href) : null;\n\n return {\n id: parseLastIdFromUrl(href || ''),\n title: nameContainer?.textContent?.trim() || null,\n url,\n info: infoContainer?.textContent?.replace(/[{()}]/g, '').trim() || null\n };\n });\n};\n\nexport const getEpisodeCode = (el: HTMLElement): string | null => {\n const filmHeaderName = el.querySelector('.film-header-name h1');\n if (!filmHeaderName) return null;\n\n const text = filmHeaderName.textContent?.trim() || '';\n const match = text.match(/\\(([^)]+)\\)/);\n const code = match ? match[1] : null;\n\n return code;\n};\n\nexport const detectSeasonOrEpisodeListType = (el: HTMLElement) => {\n const headerText = el.querySelector('.box-header h3')?.innerText.trim() ?? '';\n\n if (headerText.includes('Série')) return 'seasons';\n if (headerText.startsWith('Epizody')) return 'episodes';\n return null;\n};\n\nexport const getSeasonOrEpisodeParent = (\n el: HTMLElement,\n serie?: { id: number; title: string }\n): CSFDParent | null => {\n // Try h2 first (for episodes), then h1 (for seasons)\n let parents = el.querySelectorAll('.film-header h2 a');\n if (parents.length === 0) {\n parents = el.querySelectorAll('.film-header h1 a');\n }\n\n if (parents.length === 0) {\n if (!serie) return null;\n return { series: serie, season: null };\n }\n\n const [parentSeries, parentSeason] = parents;\n\n const seriesId = parseIdFromUrl(parentSeries?.getAttribute('href'));\n const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute('href') || '');\n const seriesTitle = parentSeries?.textContent?.trim() || null;\n const seasonTitle = parentSeason?.textContent?.trim() || null;\n\n const series = seriesId && seriesTitle ? { id: seriesId, title: seriesTitle } : null;\n const season = seasonId && seasonTitle ? { id: seasonId, title: seasonTitle } : null;\n\n if (!series && !season) return null;\n\n return { series, season };\n};\n\nexport const getMovieGroup = (\n el: HTMLElement,\n group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak\n): CSFDMovieCreator[] => {\n const creators = el.querySelectorAll('.creators h4');\n const element = creators.find((elem) => elem.textContent.trim().includes(group as string));\n if (element?.parentNode) {\n return parseMoviePeople(element.parentNode as HTMLElement);\n } else {\n return [];\n }\n};\n\nexport const getMovieType = (el: HTMLElement): CSFDFilmTypes => {\n const type = el.querySelector('.film-header-name .type');\n return parseFilmType(type?.innerText?.replace(/[{()}]/g, '') || 'film');\n};\n\nexport const getMovieVods = (el: HTMLElement | null): CSFDVod[] => {\n let vods: CSFDVod[] = [];\n if (el) {\n const buttonsVod = el.querySelectorAll('.box-buttons-vod .vod-badge a');\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 = (\n el: HTMLElement,\n boxName: CSFDBoxContent\n): 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 [dateRaw, ...company] = title?.split(' ');\n const date = parseDate(dateRaw);\n\n if (date) {\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 }\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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"}
@@ -0,0 +1,19 @@
1
+ const require_global_helper = require('./global.helper.js');
2
+
3
+ //#region src/helpers/search-creator.helper.ts
4
+ const getCreatorName = (el) => {
5
+ return el.querySelector(".user-title").text.trim();
6
+ };
7
+ const getCreatorImage = (el) => {
8
+ const image = el.querySelector("img").attributes.src;
9
+ return require_global_helper.addProtocol(image);
10
+ };
11
+ const getCreatorUrl = (el) => {
12
+ return el.querySelector(".user-title a").attributes.href;
13
+ };
14
+
15
+ //#endregion
16
+ exports.getCreatorImage = getCreatorImage;
17
+ exports.getCreatorName = getCreatorName;
18
+ exports.getCreatorUrl = getCreatorUrl;
19
+ //# sourceMappingURL=search-creator.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-creator.helper.js","names":["addProtocol"],"sources":["../../src/helpers/search-creator.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { addProtocol } from './global.helper';\n\nexport const getCreatorName = (el: HTMLElement): string => {\n return el.querySelector('.user-title').text.trim();\n};\n\nexport const getCreatorImage = (el: HTMLElement): string => {\n const image = el.querySelector('img').attributes.src;\n return addProtocol(image);\n};\n\nexport const getCreatorUrl = (el: HTMLElement): string => {\n return el.querySelector('.user-title a').attributes.href;\n};\n"],"mappings":";;;AAGA,MAAa,kBAAkB,OAA4B;AACzD,QAAO,GAAG,cAAc,cAAc,CAAC,KAAK,MAAM;;AAGpD,MAAa,mBAAmB,OAA4B;CAC1D,MAAM,QAAQ,GAAG,cAAc,MAAM,CAAC,WAAW;AACjD,QAAOA,kCAAY,MAAM;;AAG3B,MAAa,iBAAiB,OAA4B;AACxD,QAAO,GAAG,cAAc,gBAAgB,CAAC,WAAW"}
@@ -0,0 +1,17 @@
1
+ import { addProtocol } from "./global.helper.mjs";
2
+
3
+ //#region src/helpers/search-creator.helper.ts
4
+ const getCreatorName = (el) => {
5
+ return el.querySelector(".user-title").text.trim();
6
+ };
7
+ const getCreatorImage = (el) => {
8
+ const image = el.querySelector("img").attributes.src;
9
+ return addProtocol(image);
10
+ };
11
+ const getCreatorUrl = (el) => {
12
+ return el.querySelector(".user-title a").attributes.href;
13
+ };
14
+
15
+ //#endregion
16
+ export { getCreatorImage, getCreatorName, getCreatorUrl };
17
+ //# sourceMappingURL=search-creator.helper.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-creator.helper.mjs","names":[],"sources":["../../src/helpers/search-creator.helper.ts"],"sourcesContent":["import { HTMLElement } from 'node-html-parser';\nimport { addProtocol } from './global.helper';\n\nexport const getCreatorName = (el: HTMLElement): string => {\n return el.querySelector('.user-title').text.trim();\n};\n\nexport const getCreatorImage = (el: HTMLElement): string => {\n const image = el.querySelector('img').attributes.src;\n return addProtocol(image);\n};\n\nexport const getCreatorUrl = (el: HTMLElement): string => {\n return el.querySelector('.user-title a').attributes.href;\n};\n"],"mappings":";;;AAGA,MAAa,kBAAkB,OAA4B;AACzD,QAAO,GAAG,cAAc,cAAc,CAAC,KAAK,MAAM;;AAGpD,MAAa,mBAAmB,OAA4B;CAC1D,MAAM,QAAQ,GAAG,cAAc,MAAM,CAAC,WAAW;AACjD,QAAO,YAAY,MAAM;;AAG3B,MAAa,iBAAiB,OAA4B;AACxD,QAAO,GAAG,cAAc,gBAAgB,CAAC,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-csfd-api",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "ČSFD API in JavaScript. Amazing NPM library for scrapping csfd.cz :)",
5
5
  "author": "BART! <bart@bartweb.cz>",
6
6
  "publishConfig": {
@@ -12,7 +12,7 @@
12
12
  "cross-fetch": "^4.1.0",
13
13
  "dotenv": "^17.3.1",
14
14
  "express": "^5.2.1",
15
- "node-html-parser": "^7.0.2",
15
+ "node-html-parser": "^7.1.0",
16
16
  "zod": "^4.3.6"
17
17
  },
18
18
  "repository": {
package/package.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  //#region package.json
3
3
  var name = "node-csfd-api";
4
- var version = "5.1.0";
4
+ var version = "5.2.0";
5
5
  var homepage = "https://github.com/bartholomej/node-csfd-api#readme";
6
6
 
7
7
  //#endregion
@@ -1,6 +1,7 @@
1
1
  const require_index = require('../fetchers/index.js');
2
2
  const require_vars = require('../vars.js');
3
3
  const require_global_helper = require('../helpers/global.helper.js');
4
+ const require_search_creator_helper = require('../helpers/search-creator.helper.js');
4
5
  const require_search_user_helper = require('../helpers/search-user.helper.js');
5
6
  const require_search_helper = require('../helpers/search.helper.js');
6
7
  let node_html_parser = require("node-html-parser");
@@ -12,13 +13,15 @@ var SearchScraper = class {
12
13
  const moviesNode = html.querySelectorAll(".main-movies article");
13
14
  const usersNode = html.querySelectorAll(".main-users article");
14
15
  const tvSeriesNode = html.querySelectorAll(".main-series article");
15
- return this.parseSearch(moviesNode, usersNode, tvSeriesNode, options?.language);
16
+ const creatorsNode = html.querySelectorAll(".main-authors article");
17
+ return this.parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, options?.language);
16
18
  }
17
- parseSearch(moviesNode, usersNode, tvSeriesNode, language) {
19
+ parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, language) {
18
20
  const baseUrl = require_vars.getUrlByLanguage(language);
19
21
  const movies = [];
20
22
  const users = [];
21
23
  const tvSeries = [];
24
+ const creators = [];
22
25
  const movieMapper = (m) => {
23
26
  const url = require_search_helper.getSearchUrl(m);
24
27
  return {
@@ -46,14 +49,24 @@ var SearchScraper = class {
46
49
  url: `${baseUrl}${url}`
47
50
  };
48
51
  };
52
+ const creatorMapper = (m) => {
53
+ const url = require_search_creator_helper.getCreatorUrl(m);
54
+ return {
55
+ id: require_global_helper.parseIdFromUrl(url),
56
+ name: require_search_creator_helper.getCreatorName(m),
57
+ image: require_search_creator_helper.getCreatorImage(m),
58
+ url: `${baseUrl}${url}`
59
+ };
60
+ };
49
61
  movies.push(...moviesNode.map(movieMapper));
50
62
  users.push(...usersNode.map(userMapper));
51
63
  tvSeries.push(...tvSeriesNode.map(movieMapper));
64
+ creators.push(...creatorsNode.map(creatorMapper));
52
65
  return {
53
66
  movies,
54
67
  users,
55
68
  tvSeries,
56
- creators: []
69
+ creators
57
70
  };
58
71
  }
59
72
  };
@@ -1 +1 @@
1
- {"version":3,"file":"search.service.js","names":["fetchPage","searchUrl","getUrlByLanguage","getSearchUrl","parseIdFromUrl","getSearchTitle","getSearchYear","getSearchType","getSearchColorRating","getSearchPoster","getSearchOrigins","parseSearchPeople","getUserUrl","getUser","getUserRealName","getAvatar"],"sources":["../../src/services/search.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDSearch, CSFDSearchMovie, CSFDSearchUser } from '../dto/search';\nimport { fetchPage } from '../fetchers';\nimport { parseIdFromUrl } from '../helpers/global.helper';\nimport { getAvatar, getUser, getUserRealName, getUserUrl } from '../helpers/search-user.helper';\nimport {\n getSearchColorRating,\n getSearchOrigins,\n getSearchPoster,\n getSearchTitle,\n getSearchType,\n getSearchUrl,\n getSearchYear,\n parseSearchPeople\n} from '../helpers/search.helper';\nimport { CSFDLanguage, CSFDOptions } from '../types';\nimport { getUrlByLanguage, searchUrl } from '../vars';\n\nexport class SearchScraper {\n public async search(text: string, options?: CSFDOptions): Promise<CSFDSearch> {\n const url = searchUrl(text, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const html = parse(response);\n const moviesNode = html.querySelectorAll('.main-movies article');\n const usersNode = html.querySelectorAll('.main-users article');\n const tvSeriesNode = html.querySelectorAll('.main-series article');\n\n return this.parseSearch(moviesNode, usersNode, tvSeriesNode, options?.language);\n }\n\n private parseSearch(\n moviesNode: HTMLElement[],\n usersNode: HTMLElement[],\n tvSeriesNode: HTMLElement[],\n language?: CSFDLanguage\n ) {\n const baseUrl = getUrlByLanguage(language);\n\n const movies: CSFDSearchMovie[] = [];\n const users: CSFDSearchUser[] = [];\n const tvSeries: CSFDSearchMovie[] = [];\n\n const movieMapper = (m: HTMLElement): CSFDSearchMovie => {\n const url = getSearchUrl(m);\n return {\n id: parseIdFromUrl(url),\n title: getSearchTitle(m),\n year: getSearchYear(m),\n url: `${baseUrl}${url}`,\n type: getSearchType(m),\n colorRating: getSearchColorRating(m),\n poster: getSearchPoster(m),\n origins: getSearchOrigins(m),\n creators: {\n directors: parseSearchPeople(m, 'directors'),\n actors: parseSearchPeople(m, 'actors')\n }\n };\n };\n\n const userMapper = (m: HTMLElement): CSFDSearchUser => {\n const url = getUserUrl(m);\n return {\n id: parseIdFromUrl(url),\n user: getUser(m),\n userRealName: getUserRealName(m),\n avatar: getAvatar(m),\n url: `${baseUrl}${url}`\n };\n };\n\n movies.push(...moviesNode.map(movieMapper));\n users.push(...usersNode.map(userMapper));\n tvSeries.push(...tvSeriesNode.map(movieMapper));\n\n const search: CSFDSearch = {\n movies: movies,\n users: users,\n tvSeries: tvSeries,\n creators: []\n };\n return search;\n }\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,gBAAb,MAA2B;CACzB,MAAa,OAAO,MAAc,SAA4C;EAI5E,MAAM,mCAFW,MAAMA,wBADXC,uBAAU,MAAM,EAAE,UAAU,SAAS,UAAU,CAAC,EACtB,EAAE,GAAG,SAAS,SAAS,CAAC,CAElC;EAC5B,MAAM,aAAa,KAAK,iBAAiB,uBAAuB;EAChE,MAAM,YAAY,KAAK,iBAAiB,sBAAsB;EAC9D,MAAM,eAAe,KAAK,iBAAiB,uBAAuB;AAElE,SAAO,KAAK,YAAY,YAAY,WAAW,cAAc,SAAS,SAAS;;CAGjF,AAAQ,YACN,YACA,WACA,cACA,UACA;EACA,MAAM,UAAUC,8BAAiB,SAAS;EAE1C,MAAM,SAA4B,EAAE;EACpC,MAAM,QAA0B,EAAE;EAClC,MAAM,WAA8B,EAAE;EAEtC,MAAM,eAAe,MAAoC;GACvD,MAAM,MAAMC,mCAAa,EAAE;AAC3B,UAAO;IACL,IAAIC,qCAAe,IAAI;IACvB,OAAOC,qCAAe,EAAE;IACxB,MAAMC,oCAAc,EAAE;IACtB,KAAK,GAAG,UAAU;IAClB,MAAMC,oCAAc,EAAE;IACtB,aAAaC,2CAAqB,EAAE;IACpC,QAAQC,sCAAgB,EAAE;IAC1B,SAASC,uCAAiB,EAAE;IAC5B,UAAU;KACR,WAAWC,wCAAkB,GAAG,YAAY;KAC5C,QAAQA,wCAAkB,GAAG,SAAS;KACvC;IACF;;EAGH,MAAM,cAAc,MAAmC;GACrD,MAAM,MAAMC,sCAAW,EAAE;AACzB,UAAO;IACL,IAAIR,qCAAe,IAAI;IACvB,MAAMS,mCAAQ,EAAE;IAChB,cAAcC,2CAAgB,EAAE;IAChC,QAAQC,qCAAU,EAAE;IACpB,KAAK,GAAG,UAAU;IACnB;;AAGH,SAAO,KAAK,GAAG,WAAW,IAAI,YAAY,CAAC;AAC3C,QAAM,KAAK,GAAG,UAAU,IAAI,WAAW,CAAC;AACxC,WAAS,KAAK,GAAG,aAAa,IAAI,YAAY,CAAC;AAQ/C,SAN2B;GACjB;GACD;GACG;GACV,UAAU,EAAE;GACb"}
1
+ {"version":3,"file":"search.service.js","names":["fetchPage","searchUrl","getUrlByLanguage","getSearchUrl","parseIdFromUrl","getSearchTitle","getSearchYear","getSearchType","getSearchColorRating","getSearchPoster","getSearchOrigins","parseSearchPeople","getUserUrl","getUser","getUserRealName","getAvatar","getCreatorUrl","getCreatorName","getCreatorImage"],"sources":["../../src/services/search.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDSearch, CSFDSearchCreator, CSFDSearchMovie, CSFDSearchUser } from '../dto/search';\nimport { fetchPage } from '../fetchers';\nimport { parseIdFromUrl } from '../helpers/global.helper';\nimport { getCreatorImage, getCreatorName, getCreatorUrl } from '../helpers/search-creator.helper';\nimport { getAvatar, getUser, getUserRealName, getUserUrl } from '../helpers/search-user.helper';\nimport {\n getSearchColorRating,\n getSearchOrigins,\n getSearchPoster,\n getSearchTitle,\n getSearchType,\n getSearchUrl,\n getSearchYear,\n parseSearchPeople\n} from '../helpers/search.helper';\nimport { CSFDLanguage, CSFDOptions } from '../types';\nimport { getUrlByLanguage, searchUrl } from '../vars';\n\nexport class SearchScraper {\n public async search(text: string, options?: CSFDOptions): Promise<CSFDSearch> {\n const url = searchUrl(text, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const html = parse(response);\n const moviesNode = html.querySelectorAll('.main-movies article');\n const usersNode = html.querySelectorAll('.main-users article');\n const tvSeriesNode = html.querySelectorAll('.main-series article');\n const creatorsNode = html.querySelectorAll('.main-authors article');\n\n return this.parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, options?.language);\n }\n\n private parseSearch(\n moviesNode: HTMLElement[],\n usersNode: HTMLElement[],\n tvSeriesNode: HTMLElement[],\n creatorsNode: HTMLElement[],\n language?: CSFDLanguage\n ) {\n const baseUrl = getUrlByLanguage(language);\n\n const movies: CSFDSearchMovie[] = [];\n const users: CSFDSearchUser[] = [];\n const tvSeries: CSFDSearchMovie[] = [];\n const creators: CSFDSearchCreator[] = [];\n\n const movieMapper = (m: HTMLElement): CSFDSearchMovie => {\n const url = getSearchUrl(m);\n return {\n id: parseIdFromUrl(url),\n title: getSearchTitle(m),\n year: getSearchYear(m),\n url: `${baseUrl}${url}`,\n type: getSearchType(m),\n colorRating: getSearchColorRating(m),\n poster: getSearchPoster(m),\n origins: getSearchOrigins(m),\n creators: {\n directors: parseSearchPeople(m, 'directors'),\n actors: parseSearchPeople(m, 'actors')\n }\n };\n };\n\n const userMapper = (m: HTMLElement): CSFDSearchUser => {\n const url = getUserUrl(m);\n return {\n id: parseIdFromUrl(url),\n user: getUser(m),\n userRealName: getUserRealName(m),\n avatar: getAvatar(m),\n url: `${baseUrl}${url}`\n };\n };\n\n const creatorMapper = (m: HTMLElement): CSFDSearchCreator => {\n const url = getCreatorUrl(m);\n return {\n id: parseIdFromUrl(url),\n name: getCreatorName(m),\n image: getCreatorImage(m),\n url: `${baseUrl}${url}`\n };\n };\n\n movies.push(...moviesNode.map(movieMapper));\n users.push(...usersNode.map(userMapper));\n tvSeries.push(...tvSeriesNode.map(movieMapper));\n creators.push(...creatorsNode.map(creatorMapper));\n\n const search: CSFDSearch = {\n movies,\n users,\n tvSeries,\n creators\n };\n return search;\n }\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAa,gBAAb,MAA2B;CACzB,MAAa,OAAO,MAAc,SAA4C;EAI5E,MAAM,mCAFW,MAAMA,wBADXC,uBAAU,MAAM,EAAE,UAAU,SAAS,UAAU,CAAC,EACtB,EAAE,GAAG,SAAS,SAAS,CAAC,CAElC;EAC5B,MAAM,aAAa,KAAK,iBAAiB,uBAAuB;EAChE,MAAM,YAAY,KAAK,iBAAiB,sBAAsB;EAC9D,MAAM,eAAe,KAAK,iBAAiB,uBAAuB;EAClE,MAAM,eAAe,KAAK,iBAAiB,wBAAwB;AAEnE,SAAO,KAAK,YAAY,YAAY,WAAW,cAAc,cAAc,SAAS,SAAS;;CAG/F,AAAQ,YACN,YACA,WACA,cACA,cACA,UACA;EACA,MAAM,UAAUC,8BAAiB,SAAS;EAE1C,MAAM,SAA4B,EAAE;EACpC,MAAM,QAA0B,EAAE;EAClC,MAAM,WAA8B,EAAE;EACtC,MAAM,WAAgC,EAAE;EAExC,MAAM,eAAe,MAAoC;GACvD,MAAM,MAAMC,mCAAa,EAAE;AAC3B,UAAO;IACL,IAAIC,qCAAe,IAAI;IACvB,OAAOC,qCAAe,EAAE;IACxB,MAAMC,oCAAc,EAAE;IACtB,KAAK,GAAG,UAAU;IAClB,MAAMC,oCAAc,EAAE;IACtB,aAAaC,2CAAqB,EAAE;IACpC,QAAQC,sCAAgB,EAAE;IAC1B,SAASC,uCAAiB,EAAE;IAC5B,UAAU;KACR,WAAWC,wCAAkB,GAAG,YAAY;KAC5C,QAAQA,wCAAkB,GAAG,SAAS;KACvC;IACF;;EAGH,MAAM,cAAc,MAAmC;GACrD,MAAM,MAAMC,sCAAW,EAAE;AACzB,UAAO;IACL,IAAIR,qCAAe,IAAI;IACvB,MAAMS,mCAAQ,EAAE;IAChB,cAAcC,2CAAgB,EAAE;IAChC,QAAQC,qCAAU,EAAE;IACpB,KAAK,GAAG,UAAU;IACnB;;EAGH,MAAM,iBAAiB,MAAsC;GAC3D,MAAM,MAAMC,4CAAc,EAAE;AAC5B,UAAO;IACL,IAAIZ,qCAAe,IAAI;IACvB,MAAMa,6CAAe,EAAE;IACvB,OAAOC,8CAAgB,EAAE;IACzB,KAAK,GAAG,UAAU;IACnB;;AAGH,SAAO,KAAK,GAAG,WAAW,IAAI,YAAY,CAAC;AAC3C,QAAM,KAAK,GAAG,UAAU,IAAI,WAAW,CAAC;AACxC,WAAS,KAAK,GAAG,aAAa,IAAI,YAAY,CAAC;AAC/C,WAAS,KAAK,GAAG,aAAa,IAAI,cAAc,CAAC;AAQjD,SAN2B;GACzB;GACA;GACA;GACA;GACD"}
@@ -1,6 +1,7 @@
1
1
  import { fetchPage } from "../fetchers/index.mjs";
2
2
  import { getUrlByLanguage, searchUrl } from "../vars.mjs";
3
3
  import { parseIdFromUrl } from "../helpers/global.helper.mjs";
4
+ import { getCreatorImage, getCreatorName, getCreatorUrl } from "../helpers/search-creator.helper.mjs";
4
5
  import { getAvatar, getUser, getUserRealName, getUserUrl } from "../helpers/search-user.helper.mjs";
5
6
  import { getSearchColorRating, getSearchOrigins, getSearchPoster, getSearchTitle, getSearchType, getSearchUrl, getSearchYear, parseSearchPeople } from "../helpers/search.helper.mjs";
6
7
  import { parse } from "node-html-parser";
@@ -12,13 +13,15 @@ var SearchScraper = class {
12
13
  const moviesNode = html.querySelectorAll(".main-movies article");
13
14
  const usersNode = html.querySelectorAll(".main-users article");
14
15
  const tvSeriesNode = html.querySelectorAll(".main-series article");
15
- return this.parseSearch(moviesNode, usersNode, tvSeriesNode, options?.language);
16
+ const creatorsNode = html.querySelectorAll(".main-authors article");
17
+ return this.parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, options?.language);
16
18
  }
17
- parseSearch(moviesNode, usersNode, tvSeriesNode, language) {
19
+ parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, language) {
18
20
  const baseUrl = getUrlByLanguage(language);
19
21
  const movies = [];
20
22
  const users = [];
21
23
  const tvSeries = [];
24
+ const creators = [];
22
25
  const movieMapper = (m) => {
23
26
  const url = getSearchUrl(m);
24
27
  return {
@@ -46,14 +49,24 @@ var SearchScraper = class {
46
49
  url: `${baseUrl}${url}`
47
50
  };
48
51
  };
52
+ const creatorMapper = (m) => {
53
+ const url = getCreatorUrl(m);
54
+ return {
55
+ id: parseIdFromUrl(url),
56
+ name: getCreatorName(m),
57
+ image: getCreatorImage(m),
58
+ url: `${baseUrl}${url}`
59
+ };
60
+ };
49
61
  movies.push(...moviesNode.map(movieMapper));
50
62
  users.push(...usersNode.map(userMapper));
51
63
  tvSeries.push(...tvSeriesNode.map(movieMapper));
64
+ creators.push(...creatorsNode.map(creatorMapper));
52
65
  return {
53
66
  movies,
54
67
  users,
55
68
  tvSeries,
56
- creators: []
69
+ creators
57
70
  };
58
71
  }
59
72
  };
@@ -1 +1 @@
1
- {"version":3,"file":"search.service.mjs","names":[],"sources":["../../src/services/search.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDSearch, CSFDSearchMovie, CSFDSearchUser } from '../dto/search';\nimport { fetchPage } from '../fetchers';\nimport { parseIdFromUrl } from '../helpers/global.helper';\nimport { getAvatar, getUser, getUserRealName, getUserUrl } from '../helpers/search-user.helper';\nimport {\n getSearchColorRating,\n getSearchOrigins,\n getSearchPoster,\n getSearchTitle,\n getSearchType,\n getSearchUrl,\n getSearchYear,\n parseSearchPeople\n} from '../helpers/search.helper';\nimport { CSFDLanguage, CSFDOptions } from '../types';\nimport { getUrlByLanguage, searchUrl } from '../vars';\n\nexport class SearchScraper {\n public async search(text: string, options?: CSFDOptions): Promise<CSFDSearch> {\n const url = searchUrl(text, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const html = parse(response);\n const moviesNode = html.querySelectorAll('.main-movies article');\n const usersNode = html.querySelectorAll('.main-users article');\n const tvSeriesNode = html.querySelectorAll('.main-series article');\n\n return this.parseSearch(moviesNode, usersNode, tvSeriesNode, options?.language);\n }\n\n private parseSearch(\n moviesNode: HTMLElement[],\n usersNode: HTMLElement[],\n tvSeriesNode: HTMLElement[],\n language?: CSFDLanguage\n ) {\n const baseUrl = getUrlByLanguage(language);\n\n const movies: CSFDSearchMovie[] = [];\n const users: CSFDSearchUser[] = [];\n const tvSeries: CSFDSearchMovie[] = [];\n\n const movieMapper = (m: HTMLElement): CSFDSearchMovie => {\n const url = getSearchUrl(m);\n return {\n id: parseIdFromUrl(url),\n title: getSearchTitle(m),\n year: getSearchYear(m),\n url: `${baseUrl}${url}`,\n type: getSearchType(m),\n colorRating: getSearchColorRating(m),\n poster: getSearchPoster(m),\n origins: getSearchOrigins(m),\n creators: {\n directors: parseSearchPeople(m, 'directors'),\n actors: parseSearchPeople(m, 'actors')\n }\n };\n };\n\n const userMapper = (m: HTMLElement): CSFDSearchUser => {\n const url = getUserUrl(m);\n return {\n id: parseIdFromUrl(url),\n user: getUser(m),\n userRealName: getUserRealName(m),\n avatar: getAvatar(m),\n url: `${baseUrl}${url}`\n };\n };\n\n movies.push(...moviesNode.map(movieMapper));\n users.push(...usersNode.map(userMapper));\n tvSeries.push(...tvSeriesNode.map(movieMapper));\n\n const search: CSFDSearch = {\n movies: movies,\n users: users,\n tvSeries: tvSeries,\n creators: []\n };\n return search;\n }\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,gBAAb,MAA2B;CACzB,MAAa,OAAO,MAAc,SAA4C;EAI5E,MAAM,OAAO,MAFI,MAAM,UADX,UAAU,MAAM,EAAE,UAAU,SAAS,UAAU,CAAC,EACtB,EAAE,GAAG,SAAS,SAAS,CAAC,CAElC;EAC5B,MAAM,aAAa,KAAK,iBAAiB,uBAAuB;EAChE,MAAM,YAAY,KAAK,iBAAiB,sBAAsB;EAC9D,MAAM,eAAe,KAAK,iBAAiB,uBAAuB;AAElE,SAAO,KAAK,YAAY,YAAY,WAAW,cAAc,SAAS,SAAS;;CAGjF,AAAQ,YACN,YACA,WACA,cACA,UACA;EACA,MAAM,UAAU,iBAAiB,SAAS;EAE1C,MAAM,SAA4B,EAAE;EACpC,MAAM,QAA0B,EAAE;EAClC,MAAM,WAA8B,EAAE;EAEtC,MAAM,eAAe,MAAoC;GACvD,MAAM,MAAM,aAAa,EAAE;AAC3B,UAAO;IACL,IAAI,eAAe,IAAI;IACvB,OAAO,eAAe,EAAE;IACxB,MAAM,cAAc,EAAE;IACtB,KAAK,GAAG,UAAU;IAClB,MAAM,cAAc,EAAE;IACtB,aAAa,qBAAqB,EAAE;IACpC,QAAQ,gBAAgB,EAAE;IAC1B,SAAS,iBAAiB,EAAE;IAC5B,UAAU;KACR,WAAW,kBAAkB,GAAG,YAAY;KAC5C,QAAQ,kBAAkB,GAAG,SAAS;KACvC;IACF;;EAGH,MAAM,cAAc,MAAmC;GACrD,MAAM,MAAM,WAAW,EAAE;AACzB,UAAO;IACL,IAAI,eAAe,IAAI;IACvB,MAAM,QAAQ,EAAE;IAChB,cAAc,gBAAgB,EAAE;IAChC,QAAQ,UAAU,EAAE;IACpB,KAAK,GAAG,UAAU;IACnB;;AAGH,SAAO,KAAK,GAAG,WAAW,IAAI,YAAY,CAAC;AAC3C,QAAM,KAAK,GAAG,UAAU,IAAI,WAAW,CAAC;AACxC,WAAS,KAAK,GAAG,aAAa,IAAI,YAAY,CAAC;AAQ/C,SAN2B;GACjB;GACD;GACG;GACV,UAAU,EAAE;GACb"}
1
+ {"version":3,"file":"search.service.mjs","names":[],"sources":["../../src/services/search.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDSearch, CSFDSearchCreator, CSFDSearchMovie, CSFDSearchUser } from '../dto/search';\nimport { fetchPage } from '../fetchers';\nimport { parseIdFromUrl } from '../helpers/global.helper';\nimport { getCreatorImage, getCreatorName, getCreatorUrl } from '../helpers/search-creator.helper';\nimport { getAvatar, getUser, getUserRealName, getUserUrl } from '../helpers/search-user.helper';\nimport {\n getSearchColorRating,\n getSearchOrigins,\n getSearchPoster,\n getSearchTitle,\n getSearchType,\n getSearchUrl,\n getSearchYear,\n parseSearchPeople\n} from '../helpers/search.helper';\nimport { CSFDLanguage, CSFDOptions } from '../types';\nimport { getUrlByLanguage, searchUrl } from '../vars';\n\nexport class SearchScraper {\n public async search(text: string, options?: CSFDOptions): Promise<CSFDSearch> {\n const url = searchUrl(text, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const html = parse(response);\n const moviesNode = html.querySelectorAll('.main-movies article');\n const usersNode = html.querySelectorAll('.main-users article');\n const tvSeriesNode = html.querySelectorAll('.main-series article');\n const creatorsNode = html.querySelectorAll('.main-authors article');\n\n return this.parseSearch(moviesNode, usersNode, tvSeriesNode, creatorsNode, options?.language);\n }\n\n private parseSearch(\n moviesNode: HTMLElement[],\n usersNode: HTMLElement[],\n tvSeriesNode: HTMLElement[],\n creatorsNode: HTMLElement[],\n language?: CSFDLanguage\n ) {\n const baseUrl = getUrlByLanguage(language);\n\n const movies: CSFDSearchMovie[] = [];\n const users: CSFDSearchUser[] = [];\n const tvSeries: CSFDSearchMovie[] = [];\n const creators: CSFDSearchCreator[] = [];\n\n const movieMapper = (m: HTMLElement): CSFDSearchMovie => {\n const url = getSearchUrl(m);\n return {\n id: parseIdFromUrl(url),\n title: getSearchTitle(m),\n year: getSearchYear(m),\n url: `${baseUrl}${url}`,\n type: getSearchType(m),\n colorRating: getSearchColorRating(m),\n poster: getSearchPoster(m),\n origins: getSearchOrigins(m),\n creators: {\n directors: parseSearchPeople(m, 'directors'),\n actors: parseSearchPeople(m, 'actors')\n }\n };\n };\n\n const userMapper = (m: HTMLElement): CSFDSearchUser => {\n const url = getUserUrl(m);\n return {\n id: parseIdFromUrl(url),\n user: getUser(m),\n userRealName: getUserRealName(m),\n avatar: getAvatar(m),\n url: `${baseUrl}${url}`\n };\n };\n\n const creatorMapper = (m: HTMLElement): CSFDSearchCreator => {\n const url = getCreatorUrl(m);\n return {\n id: parseIdFromUrl(url),\n name: getCreatorName(m),\n image: getCreatorImage(m),\n url: `${baseUrl}${url}`\n };\n };\n\n movies.push(...moviesNode.map(movieMapper));\n users.push(...usersNode.map(userMapper));\n tvSeries.push(...tvSeriesNode.map(movieMapper));\n creators.push(...creatorsNode.map(creatorMapper));\n\n const search: CSFDSearch = {\n movies,\n users,\n tvSeries,\n creators\n };\n return search;\n }\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAa,gBAAb,MAA2B;CACzB,MAAa,OAAO,MAAc,SAA4C;EAI5E,MAAM,OAAO,MAFI,MAAM,UADX,UAAU,MAAM,EAAE,UAAU,SAAS,UAAU,CAAC,EACtB,EAAE,GAAG,SAAS,SAAS,CAAC,CAElC;EAC5B,MAAM,aAAa,KAAK,iBAAiB,uBAAuB;EAChE,MAAM,YAAY,KAAK,iBAAiB,sBAAsB;EAC9D,MAAM,eAAe,KAAK,iBAAiB,uBAAuB;EAClE,MAAM,eAAe,KAAK,iBAAiB,wBAAwB;AAEnE,SAAO,KAAK,YAAY,YAAY,WAAW,cAAc,cAAc,SAAS,SAAS;;CAG/F,AAAQ,YACN,YACA,WACA,cACA,cACA,UACA;EACA,MAAM,UAAU,iBAAiB,SAAS;EAE1C,MAAM,SAA4B,EAAE;EACpC,MAAM,QAA0B,EAAE;EAClC,MAAM,WAA8B,EAAE;EACtC,MAAM,WAAgC,EAAE;EAExC,MAAM,eAAe,MAAoC;GACvD,MAAM,MAAM,aAAa,EAAE;AAC3B,UAAO;IACL,IAAI,eAAe,IAAI;IACvB,OAAO,eAAe,EAAE;IACxB,MAAM,cAAc,EAAE;IACtB,KAAK,GAAG,UAAU;IAClB,MAAM,cAAc,EAAE;IACtB,aAAa,qBAAqB,EAAE;IACpC,QAAQ,gBAAgB,EAAE;IAC1B,SAAS,iBAAiB,EAAE;IAC5B,UAAU;KACR,WAAW,kBAAkB,GAAG,YAAY;KAC5C,QAAQ,kBAAkB,GAAG,SAAS;KACvC;IACF;;EAGH,MAAM,cAAc,MAAmC;GACrD,MAAM,MAAM,WAAW,EAAE;AACzB,UAAO;IACL,IAAI,eAAe,IAAI;IACvB,MAAM,QAAQ,EAAE;IAChB,cAAc,gBAAgB,EAAE;IAChC,QAAQ,UAAU,EAAE;IACpB,KAAK,GAAG,UAAU;IACnB;;EAGH,MAAM,iBAAiB,MAAsC;GAC3D,MAAM,MAAM,cAAc,EAAE;AAC5B,UAAO;IACL,IAAI,eAAe,IAAI;IACvB,MAAM,eAAe,EAAE;IACvB,OAAO,gBAAgB,EAAE;IACzB,KAAK,GAAG,UAAU;IACnB;;AAGH,SAAO,KAAK,GAAG,WAAW,IAAI,YAAY,CAAC;AAC3C,QAAM,KAAK,GAAG,UAAU,IAAI,WAAW,CAAC;AACxC,WAAS,KAAK,GAAG,aAAa,IAAI,YAAY,CAAC;AAC/C,WAAS,KAAK,GAAG,aAAa,IAAI,cAAc,CAAC;AAQjD,SAN2B;GACzB;GACA;GACA;GACA;GACD"}
@@ -35,12 +35,14 @@ var UserRatingsScraper = class {
35
35
  You can not use both parameters 'includesOnly' and 'excludes'.
36
36
  Parameter 'includesOnly' will be used now:`, config.includesOnly);
37
37
  }
38
+ const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;
39
+ const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;
38
40
  for (const el of movies) {
39
41
  const type = require_user_ratings_helper.getUserRatingType(el);
40
- if (config?.includesOnly?.length) {
41
- if (config.includesOnly.some((include) => type === include)) films.push(this.buildUserRatings(el, type));
42
- } else if (config?.excludes?.length) {
43
- if (!config.excludes.some((exclude) => type === exclude)) films.push(this.buildUserRatings(el, type));
42
+ if (includesSet) {
43
+ if (includesSet.has(type)) films.push(this.buildUserRatings(el, type));
44
+ } else if (excludesSet) {
45
+ if (!excludesSet.has(type)) films.push(this.buildUserRatings(el, type));
44
46
  } else films.push(this.buildUserRatings(el, type));
45
47
  }
46
48
  return films;
@@ -1 +1 @@
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('#snippet--ratings table 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('#snippet--ratings table 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, type));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserRatings(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el, type));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement, type: CSFDFilmTypes): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6BAA6B;EAGnE,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,6BAA6B;AACnE,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,IAAI,KAAK,CAAC;cAGpC,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B;GACA,KAAKC,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,0CAAc,GAAG;GAC9B"}
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('#snippet--ratings table 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('#snippet--ratings table 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 const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;\n const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;\n\n for (const el of movies) {\n const type = getUserRatingType(el);\n\n // Filtering includesOnly\n if (includesSet) {\n if (includesSet.has(type)) {\n films.push(this.buildUserRatings(el, type));\n }\n // Filter excludes\n } else if (excludesSet) {\n if (!excludesSet.has(type)) {\n films.push(this.buildUserRatings(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el, type));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement, type: CSFDFilmTypes): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6BAA6B;EAGnE,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,6BAA6B;AACnE,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;;EAIL,MAAM,cAAc,QAAQ,cAAc,SAAS,IAAI,IAAI,OAAO,aAAa,GAAG;EAClF,MAAM,cAAc,QAAQ,UAAU,SAAS,IAAI,IAAI,OAAO,SAAS,GAAG;AAE1E,OAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,OAAOC,8CAAkB,GAAG;AAGlC,OAAI,aACF;QAAI,YAAY,IAAI,KAAK,CACvB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;cAGpC,aACT;QAAI,CAAC,YAAY,IAAI,KAAK,CACxB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B;GACA,KAAKC,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,0CAAc,GAAG;GAC9B"}
@@ -35,12 +35,14 @@ var UserRatingsScraper = class {
35
35
  You can not use both parameters 'includesOnly' and 'excludes'.
36
36
  Parameter 'includesOnly' will be used now:`, config.includesOnly);
37
37
  }
38
+ const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;
39
+ const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;
38
40
  for (const el of movies) {
39
41
  const type = getUserRatingType(el);
40
- if (config?.includesOnly?.length) {
41
- if (config.includesOnly.some((include) => type === include)) films.push(this.buildUserRatings(el, type));
42
- } else if (config?.excludes?.length) {
43
- if (!config.excludes.some((exclude) => type === exclude)) films.push(this.buildUserRatings(el, type));
42
+ if (includesSet) {
43
+ if (includesSet.has(type)) films.push(this.buildUserRatings(el, type));
44
+ } else if (excludesSet) {
45
+ if (!excludesSet.has(type)) films.push(this.buildUserRatings(el, type));
44
46
  } else films.push(this.buildUserRatings(el, type));
45
47
  }
46
48
  return films;
@@ -1 +1 @@
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('#snippet--ratings table 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('#snippet--ratings table 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, type));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserRatings(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el, type));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement, type: CSFDFilmTypes): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6BAA6B;EAGnE,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,6BAA6B;AACnE,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,IAAI,KAAK,CAAC;cAGpC,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B;GACA,KAAK,iBAAiB,GAAG;GACzB,aAAa,yBAAyB,GAAG;GACzC,UAAU,kBAAkB,GAAG;GAC/B,YAAY,cAAc,GAAG;GAC9B"}
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const movies = items.querySelectorAll('#snippet--ratings table 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('#snippet--ratings table 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 const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;\n const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;\n\n for (const el of movies) {\n const type = getUserRatingType(el);\n\n // Filtering includesOnly\n if (includesSet) {\n if (includesSet.has(type)) {\n films.push(this.buildUserRatings(el, type));\n }\n // Filter excludes\n } else if (excludesSet) {\n if (!excludesSet.has(type)) {\n films.push(this.buildUserRatings(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserRatings(el, type));\n }\n }\n return films;\n }\n\n private buildUserRatings(el: HTMLElement, type: CSFDFilmTypes): CSFDUserRatings {\n return {\n id: getUserRatingId(el),\n title: getUserRatingTitle(el),\n year: getUserRatingYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,SAAS,MAAM,iBAAiB,6BAA6B;EAGnE,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,6BAA6B;AACnE,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;;EAIL,MAAM,cAAc,QAAQ,cAAc,SAAS,IAAI,IAAI,OAAO,aAAa,GAAG;EAClF,MAAM,cAAc,QAAQ,UAAU,SAAS,IAAI,IAAI,OAAO,SAAS,GAAG;AAE1E,OAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,OAAO,kBAAkB,GAAG;AAGlC,OAAI,aACF;QAAI,YAAY,IAAI,KAAK,CACvB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;cAGpC,aACT;QAAI,CAAC,YAAY,IAAI,KAAK,CACxB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B;GACA,KAAK,iBAAiB,GAAG;GACzB,aAAa,yBAAyB,GAAG;GACzC,UAAU,kBAAkB,GAAG;GAC/B,YAAY,cAAc,GAAG;GAC9B"}
@@ -35,12 +35,14 @@ var UserReviewsScraper = class {
35
35
  You can not use both parameters 'includesOnly' and 'excludes'.
36
36
  Parameter 'includesOnly' will be used now:`, config.includesOnly);
37
37
  }
38
+ const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;
39
+ const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;
38
40
  for (const el of reviews) {
39
41
  const type = require_user_reviews_helper.getUserReviewType(el);
40
- if (config?.includesOnly?.length) {
41
- if (config.includesOnly.some((include) => type === include)) films.push(this.buildUserReviews(el, type));
42
- } else if (config?.excludes?.length) {
43
- if (!config.excludes.some((exclude) => type === exclude)) films.push(this.buildUserReviews(el, type));
42
+ if (includesSet) {
43
+ if (includesSet.has(type)) films.push(this.buildUserReviews(el, type));
44
+ } else if (excludesSet) {
45
+ if (!excludesSet.has(type)) films.push(this.buildUserReviews(el, type));
44
46
  } else films.push(this.buildUserReviews(el, type));
45
47
  }
46
48
  return films;
@@ -1 +1 @@
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-tab-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-tab-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, type));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserReviews(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el, type));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement, type: CSFDFilmTypes): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,6BAA6B;EAGpE,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,6BAA6B;AACpE,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,IAAI,KAAK,CAAC;cAGpC,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B;GACA,KAAKC,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,gDAAoB,GAAG;GACnC,MAAMC,8CAAkB,GAAG;GAC3B,QAAQC,gDAAoB,GAAG;GAChC"}
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-tab-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-tab-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 const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;\n const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;\n\n for (const el of reviews) {\n const type = getUserReviewType(el);\n\n // Filtering includesOnly\n if (includesSet) {\n if (includesSet.has(type)) {\n films.push(this.buildUserReviews(el, type));\n }\n // Filter excludes\n } else if (excludesSet) {\n if (!excludesSet.has(type)) {\n films.push(this.buildUserReviews(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el, type));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement, type: CSFDFilmTypes): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,oCADW,MAAMC,wBAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,6BAA6B;EAGpE,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,6BAA6B;AACpE,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;;EAIL,MAAM,cAAc,QAAQ,cAAc,SAAS,IAAI,IAAI,OAAO,aAAa,GAAG;EAClF,MAAM,cAAc,QAAQ,UAAU,SAAS,IAAI,IAAI,OAAO,SAAS,GAAG;AAE1E,OAAK,MAAM,MAAM,SAAS;GACxB,MAAM,OAAOC,8CAAkB,GAAG;AAGlC,OAAI,aACF;QAAI,YAAY,IAAI,KAAK,CACvB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;cAGpC,aACT;QAAI,CAAC,YAAY,IAAI,KAAK,CACxB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAIC,4CAAgB,GAAG;GACvB,OAAOC,+CAAmB,GAAG;GAC7B,MAAMC,8CAAkB,GAAG;GAC3B;GACA,KAAKC,6CAAiB,GAAG;GACzB,aAAaC,qDAAyB,GAAG;GACzC,UAAUC,8CAAkB,GAAG;GAC/B,YAAYC,gDAAoB,GAAG;GACnC,MAAMC,8CAAkB,GAAG;GAC3B,QAAQC,gDAAoB,GAAG;GAChC"}
@@ -35,12 +35,14 @@ var UserReviewsScraper = class {
35
35
  You can not use both parameters 'includesOnly' and 'excludes'.
36
36
  Parameter 'includesOnly' will be used now:`, config.includesOnly);
37
37
  }
38
+ const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;
39
+ const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;
38
40
  for (const el of reviews) {
39
41
  const type = getUserReviewType(el);
40
- if (config?.includesOnly?.length) {
41
- if (config.includesOnly.some((include) => type === include)) films.push(this.buildUserReviews(el, type));
42
- } else if (config?.excludes?.length) {
43
- if (!config.excludes.some((exclude) => type === exclude)) films.push(this.buildUserReviews(el, type));
42
+ if (includesSet) {
43
+ if (includesSet.has(type)) films.push(this.buildUserReviews(el, type));
44
+ } else if (excludesSet) {
45
+ if (!excludesSet.has(type)) films.push(this.buildUserReviews(el, type));
44
46
  } else films.push(this.buildUserReviews(el, type));
45
47
  }
46
48
  return films;
@@ -1 +1 @@
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-tab-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-tab-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, type));\n }\n // Filter excludes\n } else if (config?.excludes?.length) {\n if (!config.excludes.some((exclude) => type === exclude)) {\n films.push(this.buildUserReviews(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el, type));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement, type: CSFDFilmTypes): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,6BAA6B;EAGpE,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,6BAA6B;AACpE,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,IAAI,KAAK,CAAC;cAGpC,QAAQ,UAAU,QAC3B;QAAI,CAAC,OAAO,SAAS,MAAM,YAAY,SAAS,QAAQ,CACtD,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B;GACA,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"}
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, CSFDFilmTypes, 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, {\n language: options?.language\n });\n const response = await fetchPage(url, { ...options?.request });\n const items = parse(response);\n const reviews = items.querySelectorAll('.user-tab-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-tab-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 const includesSet = config?.includesOnly?.length ? new Set(config.includesOnly) : null;\n const excludesSet = config?.excludes?.length ? new Set(config.excludes) : null;\n\n for (const el of reviews) {\n const type = getUserReviewType(el);\n\n // Filtering includesOnly\n if (includesSet) {\n if (includesSet.has(type)) {\n films.push(this.buildUserReviews(el, type));\n }\n // Filter excludes\n } else if (excludesSet) {\n if (!excludesSet.has(type)) {\n films.push(this.buildUserReviews(el, type));\n }\n } else {\n // Without filtering\n films.push(this.buildUserReviews(el, type));\n }\n }\n return films;\n }\n\n private buildUserReviews(el: HTMLElement, type: CSFDFilmTypes): CSFDUserReviews {\n return {\n id: getUserReviewId(el),\n title: getUserReviewTitle(el),\n year: getUserReviewYear(el),\n type,\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,EAC1E,UAAU,SAAS,UACpB,CAAC;EAEF,MAAM,QAAQ,MADG,MAAM,UAAU,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC,CACjC;EAC7B,MAAM,UAAU,MAAM,iBAAiB,6BAA6B;EAGpE,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,6BAA6B;AACpE,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;;EAIL,MAAM,cAAc,QAAQ,cAAc,SAAS,IAAI,IAAI,OAAO,aAAa,GAAG;EAClF,MAAM,cAAc,QAAQ,UAAU,SAAS,IAAI,IAAI,OAAO,SAAS,GAAG;AAE1E,OAAK,MAAM,MAAM,SAAS;GACxB,MAAM,OAAO,kBAAkB,GAAG;AAGlC,OAAI,aACF;QAAI,YAAY,IAAI,KAAK,CACvB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;cAGpC,aACT;QAAI,CAAC,YAAY,IAAI,KAAK,CACxB,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;SAI7C,OAAM,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC;;AAG/C,SAAO;;CAGT,AAAQ,iBAAiB,IAAiB,MAAsC;AAC9E,SAAO;GACL,IAAI,gBAAgB,GAAG;GACvB,OAAO,mBAAmB,GAAG;GAC7B,MAAM,kBAAkB,GAAG;GAC3B;GACA,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"}