node-csfd-api 5.0.0-next.1 → 5.0.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dto/movie.d.mts CHANGED
@@ -18,6 +18,21 @@ interface CSFDMovie extends CSFDScreening {
18
18
  premieres: CSFDPremiere[];
19
19
  related: CSFDMovieListItem[];
20
20
  similar: CSFDMovieListItem[];
21
+ seasons: CSFDSeriesChild[] | null;
22
+ episodes: CSFDSeriesChild[] | null;
23
+ parent: CSFDParent | null;
24
+ episodeCode: string | null;
25
+ seasonName: string | null;
26
+ }
27
+ interface CSFDParent {
28
+ season: {
29
+ id: number;
30
+ title: string;
31
+ } | null;
32
+ series: {
33
+ id: number;
34
+ title: string;
35
+ } | null;
21
36
  }
22
37
  interface MovieJsonLd {
23
38
  dateCreated?: string;
@@ -73,6 +88,12 @@ interface CSFDPremiere {
73
88
  company: string;
74
89
  }
75
90
  type CSFDBoxContent = 'Související' | 'Podobné';
91
+ interface CSFDSeriesChild {
92
+ id: number;
93
+ title: string;
94
+ url: string;
95
+ info: string | null;
96
+ }
76
97
  //#endregion
77
- export { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd };
98
+ export { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDSeriesChild, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd };
78
99
  //# sourceMappingURL=movie.d.mts.map
package/dto/movie.d.ts CHANGED
@@ -18,6 +18,21 @@ interface CSFDMovie extends CSFDScreening {
18
18
  premieres: CSFDPremiere[];
19
19
  related: CSFDMovieListItem[];
20
20
  similar: CSFDMovieListItem[];
21
+ seasons: CSFDSeriesChild[] | null;
22
+ episodes: CSFDSeriesChild[] | null;
23
+ parent: CSFDParent | null;
24
+ episodeCode: string | null;
25
+ seasonName: string | null;
26
+ }
27
+ interface CSFDParent {
28
+ season: {
29
+ id: number;
30
+ title: string;
31
+ } | null;
32
+ series: {
33
+ id: number;
34
+ title: string;
35
+ } | null;
21
36
  }
22
37
  interface MovieJsonLd {
23
38
  dateCreated?: string;
@@ -73,6 +88,12 @@ interface CSFDPremiere {
73
88
  company: string;
74
89
  }
75
90
  type CSFDBoxContent = 'Související' | 'Podobné';
91
+ interface CSFDSeriesChild {
92
+ id: number;
93
+ title: string;
94
+ url: string;
95
+ info: string | null;
96
+ }
76
97
  //#endregion
77
- export { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd };
98
+ export { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDSeriesChild, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd };
78
99
  //# sourceMappingURL=movie.d.ts.map
@@ -7,6 +7,10 @@ const parseIdFromUrl = (url) => {
7
7
  const parts = url.split("/");
8
8
  return +parts[LANG_PREFIX_REGEX.test(parts[1]) ? 3 : 2]?.split("-")[0] || null;
9
9
  };
10
+ const parseLastIdFromUrl = (url) => {
11
+ if (url) return +(url?.split("/")[3])?.split("-")[0] || null;
12
+ else return null;
13
+ };
10
14
  const getColor = (cls) => {
11
15
  switch (cls) {
12
16
  case "page-lightgrey": return "unknown";
@@ -99,5 +103,6 @@ exports.parseDate = parseDate;
99
103
  exports.parseFilmType = parseFilmType;
100
104
  exports.parseISO8601Duration = parseISO8601Duration;
101
105
  exports.parseIdFromUrl = parseIdFromUrl;
106
+ exports.parseLastIdFromUrl = parseLastIdFromUrl;
102
107
  exports.sleep = sleep;
103
108
  //# sourceMappingURL=global.helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"global.helper.js","names":[],"sources":["../../src/helpers/global.helper.ts"],"sourcesContent":["import { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDColors } from '../dto/user-ratings';\n\nconst LANG_PREFIX_REGEX = /^[a-z]{2,3}$/;\nconst ISO8601_DURATION_REGEX =\n /(-)?P(?:([.,\\d]+)Y)?(?:([.,\\d]+)M)?(?:([.,\\d]+)W)?(?:([.,\\d]+)D)?T(?:([.,\\d]+)H)?(?:([.,\\d]+)M)?(?:([.,\\d]+)S)?/;\n\nexport const parseIdFromUrl = (url: string): number => {\n if (!url) return null;\n\n const parts = url.split('/');\n // Detect language prefix like /en/ or /sk/\n const hasLangPrefix = LANG_PREFIX_REGEX.test(parts[1]);\n const idSlug = parts[hasLangPrefix ? 3 : 2];\n const id = idSlug?.split('-')[0];\n return +id || null;\n};\n\nexport const getColor = (cls: string): CSFDColorRating => {\n switch (cls) {\n case 'page-lightgrey':\n return 'unknown';\n case 'page-red':\n return 'good';\n case 'page-blue':\n return 'average';\n case 'page-grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nexport const parseColor = (quality: CSFDColors): CSFDColorRating => {\n switch (quality) {\n case 'lightgrey':\n return 'unknown';\n case 'red':\n return 'good';\n case 'blue':\n return 'average';\n case 'grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nconst filmTypeMap: Record<string, CSFDFilmTypes> = {\n 'TV film': 'tv-film',\n pořad: 'tv-show',\n seriál: 'series',\n 'divadelní záznam': 'theatrical',\n koncert: 'concert',\n série: 'season',\n 'studentský film': 'student-film',\n 'amatérský film': 'amateur-film',\n 'hudební videoklip': 'music-video',\n epizoda: 'episode',\n 'video kompilace': 'video-compilation',\n film: 'film'\n};\n\nexport const parseFilmType = (type: string): CSFDFilmTypes => {\n return filmTypeMap[type] || 'film';\n};\n\nexport const addProtocol = (url: string): string => {\n return url.startsWith('//') ? 'https:' + url : url;\n};\n\nexport const getDuration = (matches: RegExpMatchArray) => {\n return {\n sign: matches[1] === undefined ? '+' : '-',\n years: matches[2] === undefined ? 0 : matches[2],\n months: matches[3] === undefined ? 0 : matches[3],\n weeks: matches[4] === undefined ? 0 : matches[4],\n days: matches[5] === undefined ? 0 : matches[5],\n hours: matches[6] === undefined ? 0 : matches[6],\n minutes: matches[7] === undefined ? 0 : matches[7],\n seconds: matches[8] === undefined ? 0 : matches[8]\n };\n};\n\nexport const parseISO8601Duration = (iso: string): number => {\n const matches = iso.match(ISO8601_DURATION_REGEX);\n\n const duration = getDuration(matches);\n\n return +duration.hours * 60 + +duration.minutes;\n};\n\n/**\n * Parses a date string into a standardized YYYY-MM-DD format.\n * Supports:\n * - D.M.YYYY\n * - DD.MM.YYYY\n * - D. M. YYYY\n * - MM/DD/YYYY\n * - YYYY\n */\nexport const parseDate = (date: string): string | null => {\n if (!date) return null;\n\n // Clean the input\n const cleanDate = date.trim();\n\n // Try parsing DD.MM.YYYY or D.M.YYYY with optional spaces\n const dateMatch = cleanDate.match(/^(\\d{1,2})\\.\\s*(\\d{1,2})\\.\\s*(\\d{4})$/);\n if (dateMatch) {\n const day = dateMatch[1].padStart(2, '0');\n const month = dateMatch[2].padStart(2, '0');\n const year = dateMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing MM/DD/YYYY\n const slashMatch = cleanDate.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n if (slashMatch) {\n const month = slashMatch[1].padStart(2, '0');\n const day = slashMatch[2].padStart(2, '0');\n const year = slashMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing YYYY\n const yearMatch = cleanDate.match(/^(\\d{4})$/);\n if (yearMatch) {\n return `${yearMatch[1]}-01-01`;\n }\n\n return null;\n};\n\n// Sleep in loop\nexport const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));\n"],"mappings":";;AAGA,MAAM,oBAAoB;AAC1B,MAAM,yBACJ;AAEF,MAAa,kBAAkB,QAAwB;AACrD,KAAI,CAAC,IAAK,QAAO;CAEjB,MAAM,QAAQ,IAAI,MAAM,IAAI;AAK5B,QAAO,CAFQ,MADO,kBAAkB,KAAK,MAAM,GAAG,GACjB,IAAI,IACtB,MAAM,IAAI,CAAC,MAChB;;AAGhB,MAAa,YAAY,QAAiC;AACxD,SAAQ,KAAR;EACE,KAAK,iBACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAa,cAAc,YAAyC;AAClE,SAAQ,SAAR;EACE,KAAK,YACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAM,cAA6C;CACjD,WAAW;CACX,OAAO;CACP,QAAQ;CACR,oBAAoB;CACpB,SAAS;CACT,OAAO;CACP,mBAAmB;CACnB,kBAAkB;CAClB,qBAAqB;CACrB,SAAS;CACT,mBAAmB;CACnB,MAAM;CACP;AAED,MAAa,iBAAiB,SAAgC;AAC5D,QAAO,YAAY,SAAS;;AAG9B,MAAa,eAAe,QAAwB;AAClD,QAAO,IAAI,WAAW,KAAK,GAAG,WAAW,MAAM;;AAGjD,MAAa,eAAe,YAA8B;AACxD,QAAO;EACL,MAAM,QAAQ,OAAO,SAAY,MAAM;EACvC,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,QAAQ,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC/C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,MAAM,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC7C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAChD,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EACjD;;AAGH,MAAa,wBAAwB,QAAwB;CAG3D,MAAM,WAAW,YAFD,IAAI,MAAM,uBAAuB,CAEZ;AAErC,QAAO,CAAC,SAAS,QAAQ,KAAK,CAAC,SAAS;;;;;;;;;;;AAY1C,MAAa,aAAa,SAAgC;AACxD,KAAI,CAAC,KAAM,QAAO;CAGlB,MAAM,YAAY,KAAK,MAAM;CAG7B,MAAM,YAAY,UAAU,MAAM,wCAAwC;AAC1E,KAAI,WAAW;EACb,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI;EACzC,MAAM,QAAQ,UAAU,GAAG,SAAS,GAAG,IAAI;AAE3C,SAAO,GADM,UAAU,GACR,GAAG,MAAM,GAAG;;CAI7B,MAAM,aAAa,UAAU,MAAM,kCAAkC;AACrE,KAAI,YAAY;EACd,MAAM,QAAQ,WAAW,GAAG,SAAS,GAAG,IAAI;EAC5C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI;AAE1C,SAAO,GADM,WAAW,GACT,GAAG,MAAM,GAAG;;CAI7B,MAAM,YAAY,UAAU,MAAM,YAAY;AAC9C,KAAI,UACF,QAAO,GAAG,UAAU,GAAG;AAGzB,QAAO;;AAIT,MAAa,SAAS,OAAe,IAAI,SAAS,QAAQ,WAAW,KAAK,GAAG,CAAC"}
1
+ {"version":3,"file":"global.helper.js","names":[],"sources":["../../src/helpers/global.helper.ts"],"sourcesContent":["import { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDColors } from '../dto/user-ratings';\n\nconst LANG_PREFIX_REGEX = /^[a-z]{2,3}$/;\nconst ISO8601_DURATION_REGEX =\n /(-)?P(?:([.,\\d]+)Y)?(?:([.,\\d]+)M)?(?:([.,\\d]+)W)?(?:([.,\\d]+)D)?T(?:([.,\\d]+)H)?(?:([.,\\d]+)M)?(?:([.,\\d]+)S)?/;\n\nexport const parseIdFromUrl = (url: string): number => {\n if (!url) return null;\n\n const parts = url.split('/');\n // Detect language prefix like /en/ or /sk/\n const hasLangPrefix = LANG_PREFIX_REGEX.test(parts[1]);\n const idSlug = parts[hasLangPrefix ? 3 : 2];\n const id = idSlug?.split('-')[0];\n return +id || null;\n};\n\nexport const parseLastIdFromUrl = (url: string): number => {\n if (url) {\n const idSlug = url?.split('/')[3];\n const id = idSlug?.split('-')[0];\n return +id || null;\n } else {\n return null;\n }\n};\n\nexport const getColor = (cls: string): CSFDColorRating => {\n switch (cls) {\n case 'page-lightgrey':\n return 'unknown';\n case 'page-red':\n return 'good';\n case 'page-blue':\n return 'average';\n case 'page-grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nexport const parseColor = (quality: CSFDColors): CSFDColorRating => {\n switch (quality) {\n case 'lightgrey':\n return 'unknown';\n case 'red':\n return 'good';\n case 'blue':\n return 'average';\n case 'grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nconst filmTypeMap: Record<string, CSFDFilmTypes> = {\n 'TV film': 'tv-film',\n pořad: 'tv-show',\n seriál: 'series',\n 'divadelní záznam': 'theatrical',\n koncert: 'concert',\n série: 'season',\n 'studentský film': 'student-film',\n 'amatérský film': 'amateur-film',\n 'hudební videoklip': 'music-video',\n epizoda: 'episode',\n 'video kompilace': 'video-compilation',\n film: 'film'\n};\n\nexport const parseFilmType = (type: string): CSFDFilmTypes => {\n return filmTypeMap[type] || 'film';\n};\n\nexport const addProtocol = (url: string): string => {\n return url.startsWith('//') ? 'https:' + url : url;\n};\n\nexport const getDuration = (matches: RegExpMatchArray) => {\n return {\n sign: matches[1] === undefined ? '+' : '-',\n years: matches[2] === undefined ? 0 : matches[2],\n months: matches[3] === undefined ? 0 : matches[3],\n weeks: matches[4] === undefined ? 0 : matches[4],\n days: matches[5] === undefined ? 0 : matches[5],\n hours: matches[6] === undefined ? 0 : matches[6],\n minutes: matches[7] === undefined ? 0 : matches[7],\n seconds: matches[8] === undefined ? 0 : matches[8]\n };\n};\n\nexport const parseISO8601Duration = (iso: string): number => {\n const matches = iso.match(ISO8601_DURATION_REGEX);\n\n const duration = getDuration(matches);\n\n return +duration.hours * 60 + +duration.minutes;\n};\n\n/**\n * Parses a date string into a standardized YYYY-MM-DD format.\n * Supports:\n * - D.M.YYYY\n * - DD.MM.YYYY\n * - D. M. YYYY\n * - MM/DD/YYYY\n * - YYYY\n */\nexport const parseDate = (date: string): string | null => {\n if (!date) return null;\n\n // Clean the input\n const cleanDate = date.trim();\n\n // Try parsing DD.MM.YYYY or D.M.YYYY with optional spaces\n const dateMatch = cleanDate.match(/^(\\d{1,2})\\.\\s*(\\d{1,2})\\.\\s*(\\d{4})$/);\n if (dateMatch) {\n const day = dateMatch[1].padStart(2, '0');\n const month = dateMatch[2].padStart(2, '0');\n const year = dateMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing MM/DD/YYYY\n const slashMatch = cleanDate.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n if (slashMatch) {\n const month = slashMatch[1].padStart(2, '0');\n const day = slashMatch[2].padStart(2, '0');\n const year = slashMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing YYYY\n const yearMatch = cleanDate.match(/^(\\d{4})$/);\n if (yearMatch) {\n return `${yearMatch[1]}-01-01`;\n }\n\n return null;\n};\n\n// Sleep in loop\nexport const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));\n"],"mappings":";;AAGA,MAAM,oBAAoB;AAC1B,MAAM,yBACJ;AAEF,MAAa,kBAAkB,QAAwB;AACrD,KAAI,CAAC,IAAK,QAAO;CAEjB,MAAM,QAAQ,IAAI,MAAM,IAAI;AAK5B,QAAO,CAFQ,MADO,kBAAkB,KAAK,MAAM,GAAG,GACjB,IAAI,IACtB,MAAM,IAAI,CAAC,MAChB;;AAGhB,MAAa,sBAAsB,QAAwB;AACzD,KAAI,IAGF,QAAO,EAFQ,KAAK,MAAM,IAAI,CAAC,KACZ,MAAM,IAAI,CAAC,MAChB;KAEd,QAAO;;AAIX,MAAa,YAAY,QAAiC;AACxD,SAAQ,KAAR;EACE,KAAK,iBACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAa,cAAc,YAAyC;AAClE,SAAQ,SAAR;EACE,KAAK,YACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAM,cAA6C;CACjD,WAAW;CACX,OAAO;CACP,QAAQ;CACR,oBAAoB;CACpB,SAAS;CACT,OAAO;CACP,mBAAmB;CACnB,kBAAkB;CAClB,qBAAqB;CACrB,SAAS;CACT,mBAAmB;CACnB,MAAM;CACP;AAED,MAAa,iBAAiB,SAAgC;AAC5D,QAAO,YAAY,SAAS;;AAG9B,MAAa,eAAe,QAAwB;AAClD,QAAO,IAAI,WAAW,KAAK,GAAG,WAAW,MAAM;;AAGjD,MAAa,eAAe,YAA8B;AACxD,QAAO;EACL,MAAM,QAAQ,OAAO,SAAY,MAAM;EACvC,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,QAAQ,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC/C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,MAAM,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC7C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAChD,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EACjD;;AAGH,MAAa,wBAAwB,QAAwB;CAG3D,MAAM,WAAW,YAFD,IAAI,MAAM,uBAAuB,CAEZ;AAErC,QAAO,CAAC,SAAS,QAAQ,KAAK,CAAC,SAAS;;;;;;;;;;;AAY1C,MAAa,aAAa,SAAgC;AACxD,KAAI,CAAC,KAAM,QAAO;CAGlB,MAAM,YAAY,KAAK,MAAM;CAG7B,MAAM,YAAY,UAAU,MAAM,wCAAwC;AAC1E,KAAI,WAAW;EACb,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI;EACzC,MAAM,QAAQ,UAAU,GAAG,SAAS,GAAG,IAAI;AAE3C,SAAO,GADM,UAAU,GACR,GAAG,MAAM,GAAG;;CAI7B,MAAM,aAAa,UAAU,MAAM,kCAAkC;AACrE,KAAI,YAAY;EACd,MAAM,QAAQ,WAAW,GAAG,SAAS,GAAG,IAAI;EAC5C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI;AAE1C,SAAO,GADM,WAAW,GACT,GAAG,MAAM,GAAG;;CAI7B,MAAM,YAAY,UAAU,MAAM,YAAY;AAC9C,KAAI,UACF,QAAO,GAAG,UAAU,GAAG;AAGzB,QAAO;;AAIT,MAAa,SAAS,OAAe,IAAI,SAAS,QAAQ,WAAW,KAAK,GAAG,CAAC"}
@@ -6,6 +6,10 @@ const parseIdFromUrl = (url) => {
6
6
  const parts = url.split("/");
7
7
  return +parts[LANG_PREFIX_REGEX.test(parts[1]) ? 3 : 2]?.split("-")[0] || null;
8
8
  };
9
+ const parseLastIdFromUrl = (url) => {
10
+ if (url) return +(url?.split("/")[3])?.split("-")[0] || null;
11
+ else return null;
12
+ };
9
13
  const getColor = (cls) => {
10
14
  switch (cls) {
11
15
  case "page-lightgrey": return "unknown";
@@ -91,5 +95,5 @@ const parseDate = (date) => {
91
95
  const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
92
96
 
93
97
  //#endregion
94
- export { addProtocol, getColor, parseColor, parseDate, parseFilmType, parseISO8601Duration, parseIdFromUrl, sleep };
98
+ export { addProtocol, getColor, parseColor, parseDate, parseFilmType, parseISO8601Duration, parseIdFromUrl, parseLastIdFromUrl, sleep };
95
99
  //# sourceMappingURL=global.helper.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"global.helper.mjs","names":[],"sources":["../../src/helpers/global.helper.ts"],"sourcesContent":["import { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDColors } from '../dto/user-ratings';\n\nconst LANG_PREFIX_REGEX = /^[a-z]{2,3}$/;\nconst ISO8601_DURATION_REGEX =\n /(-)?P(?:([.,\\d]+)Y)?(?:([.,\\d]+)M)?(?:([.,\\d]+)W)?(?:([.,\\d]+)D)?T(?:([.,\\d]+)H)?(?:([.,\\d]+)M)?(?:([.,\\d]+)S)?/;\n\nexport const parseIdFromUrl = (url: string): number => {\n if (!url) return null;\n\n const parts = url.split('/');\n // Detect language prefix like /en/ or /sk/\n const hasLangPrefix = LANG_PREFIX_REGEX.test(parts[1]);\n const idSlug = parts[hasLangPrefix ? 3 : 2];\n const id = idSlug?.split('-')[0];\n return +id || null;\n};\n\nexport const getColor = (cls: string): CSFDColorRating => {\n switch (cls) {\n case 'page-lightgrey':\n return 'unknown';\n case 'page-red':\n return 'good';\n case 'page-blue':\n return 'average';\n case 'page-grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nexport const parseColor = (quality: CSFDColors): CSFDColorRating => {\n switch (quality) {\n case 'lightgrey':\n return 'unknown';\n case 'red':\n return 'good';\n case 'blue':\n return 'average';\n case 'grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nconst filmTypeMap: Record<string, CSFDFilmTypes> = {\n 'TV film': 'tv-film',\n pořad: 'tv-show',\n seriál: 'series',\n 'divadelní záznam': 'theatrical',\n koncert: 'concert',\n série: 'season',\n 'studentský film': 'student-film',\n 'amatérský film': 'amateur-film',\n 'hudební videoklip': 'music-video',\n epizoda: 'episode',\n 'video kompilace': 'video-compilation',\n film: 'film'\n};\n\nexport const parseFilmType = (type: string): CSFDFilmTypes => {\n return filmTypeMap[type] || 'film';\n};\n\nexport const addProtocol = (url: string): string => {\n return url.startsWith('//') ? 'https:' + url : url;\n};\n\nexport const getDuration = (matches: RegExpMatchArray) => {\n return {\n sign: matches[1] === undefined ? '+' : '-',\n years: matches[2] === undefined ? 0 : matches[2],\n months: matches[3] === undefined ? 0 : matches[3],\n weeks: matches[4] === undefined ? 0 : matches[4],\n days: matches[5] === undefined ? 0 : matches[5],\n hours: matches[6] === undefined ? 0 : matches[6],\n minutes: matches[7] === undefined ? 0 : matches[7],\n seconds: matches[8] === undefined ? 0 : matches[8]\n };\n};\n\nexport const parseISO8601Duration = (iso: string): number => {\n const matches = iso.match(ISO8601_DURATION_REGEX);\n\n const duration = getDuration(matches);\n\n return +duration.hours * 60 + +duration.minutes;\n};\n\n/**\n * Parses a date string into a standardized YYYY-MM-DD format.\n * Supports:\n * - D.M.YYYY\n * - DD.MM.YYYY\n * - D. M. YYYY\n * - MM/DD/YYYY\n * - YYYY\n */\nexport const parseDate = (date: string): string | null => {\n if (!date) return null;\n\n // Clean the input\n const cleanDate = date.trim();\n\n // Try parsing DD.MM.YYYY or D.M.YYYY with optional spaces\n const dateMatch = cleanDate.match(/^(\\d{1,2})\\.\\s*(\\d{1,2})\\.\\s*(\\d{4})$/);\n if (dateMatch) {\n const day = dateMatch[1].padStart(2, '0');\n const month = dateMatch[2].padStart(2, '0');\n const year = dateMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing MM/DD/YYYY\n const slashMatch = cleanDate.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n if (slashMatch) {\n const month = slashMatch[1].padStart(2, '0');\n const day = slashMatch[2].padStart(2, '0');\n const year = slashMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing YYYY\n const yearMatch = cleanDate.match(/^(\\d{4})$/);\n if (yearMatch) {\n return `${yearMatch[1]}-01-01`;\n }\n\n return null;\n};\n\n// Sleep in loop\nexport const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));\n"],"mappings":";AAGA,MAAM,oBAAoB;AAC1B,MAAM,yBACJ;AAEF,MAAa,kBAAkB,QAAwB;AACrD,KAAI,CAAC,IAAK,QAAO;CAEjB,MAAM,QAAQ,IAAI,MAAM,IAAI;AAK5B,QAAO,CAFQ,MADO,kBAAkB,KAAK,MAAM,GAAG,GACjB,IAAI,IACtB,MAAM,IAAI,CAAC,MAChB;;AAGhB,MAAa,YAAY,QAAiC;AACxD,SAAQ,KAAR;EACE,KAAK,iBACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAa,cAAc,YAAyC;AAClE,SAAQ,SAAR;EACE,KAAK,YACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAM,cAA6C;CACjD,WAAW;CACX,OAAO;CACP,QAAQ;CACR,oBAAoB;CACpB,SAAS;CACT,OAAO;CACP,mBAAmB;CACnB,kBAAkB;CAClB,qBAAqB;CACrB,SAAS;CACT,mBAAmB;CACnB,MAAM;CACP;AAED,MAAa,iBAAiB,SAAgC;AAC5D,QAAO,YAAY,SAAS;;AAG9B,MAAa,eAAe,QAAwB;AAClD,QAAO,IAAI,WAAW,KAAK,GAAG,WAAW,MAAM;;AAGjD,MAAa,eAAe,YAA8B;AACxD,QAAO;EACL,MAAM,QAAQ,OAAO,SAAY,MAAM;EACvC,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,QAAQ,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC/C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,MAAM,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC7C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAChD,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EACjD;;AAGH,MAAa,wBAAwB,QAAwB;CAG3D,MAAM,WAAW,YAFD,IAAI,MAAM,uBAAuB,CAEZ;AAErC,QAAO,CAAC,SAAS,QAAQ,KAAK,CAAC,SAAS;;;;;;;;;;;AAY1C,MAAa,aAAa,SAAgC;AACxD,KAAI,CAAC,KAAM,QAAO;CAGlB,MAAM,YAAY,KAAK,MAAM;CAG7B,MAAM,YAAY,UAAU,MAAM,wCAAwC;AAC1E,KAAI,WAAW;EACb,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI;EACzC,MAAM,QAAQ,UAAU,GAAG,SAAS,GAAG,IAAI;AAE3C,SAAO,GADM,UAAU,GACR,GAAG,MAAM,GAAG;;CAI7B,MAAM,aAAa,UAAU,MAAM,kCAAkC;AACrE,KAAI,YAAY;EACd,MAAM,QAAQ,WAAW,GAAG,SAAS,GAAG,IAAI;EAC5C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI;AAE1C,SAAO,GADM,WAAW,GACT,GAAG,MAAM,GAAG;;CAI7B,MAAM,YAAY,UAAU,MAAM,YAAY;AAC9C,KAAI,UACF,QAAO,GAAG,UAAU,GAAG;AAGzB,QAAO;;AAIT,MAAa,SAAS,OAAe,IAAI,SAAS,QAAQ,WAAW,KAAK,GAAG,CAAC"}
1
+ {"version":3,"file":"global.helper.mjs","names":[],"sources":["../../src/helpers/global.helper.ts"],"sourcesContent":["import { CSFDColorRating, CSFDFilmTypes } from '../dto/global';\nimport { CSFDColors } from '../dto/user-ratings';\n\nconst LANG_PREFIX_REGEX = /^[a-z]{2,3}$/;\nconst ISO8601_DURATION_REGEX =\n /(-)?P(?:([.,\\d]+)Y)?(?:([.,\\d]+)M)?(?:([.,\\d]+)W)?(?:([.,\\d]+)D)?T(?:([.,\\d]+)H)?(?:([.,\\d]+)M)?(?:([.,\\d]+)S)?/;\n\nexport const parseIdFromUrl = (url: string): number => {\n if (!url) return null;\n\n const parts = url.split('/');\n // Detect language prefix like /en/ or /sk/\n const hasLangPrefix = LANG_PREFIX_REGEX.test(parts[1]);\n const idSlug = parts[hasLangPrefix ? 3 : 2];\n const id = idSlug?.split('-')[0];\n return +id || null;\n};\n\nexport const parseLastIdFromUrl = (url: string): number => {\n if (url) {\n const idSlug = url?.split('/')[3];\n const id = idSlug?.split('-')[0];\n return +id || null;\n } else {\n return null;\n }\n};\n\nexport const getColor = (cls: string): CSFDColorRating => {\n switch (cls) {\n case 'page-lightgrey':\n return 'unknown';\n case 'page-red':\n return 'good';\n case 'page-blue':\n return 'average';\n case 'page-grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nexport const parseColor = (quality: CSFDColors): CSFDColorRating => {\n switch (quality) {\n case 'lightgrey':\n return 'unknown';\n case 'red':\n return 'good';\n case 'blue':\n return 'average';\n case 'grey':\n return 'bad';\n default:\n return 'unknown';\n }\n};\n\nconst filmTypeMap: Record<string, CSFDFilmTypes> = {\n 'TV film': 'tv-film',\n pořad: 'tv-show',\n seriál: 'series',\n 'divadelní záznam': 'theatrical',\n koncert: 'concert',\n série: 'season',\n 'studentský film': 'student-film',\n 'amatérský film': 'amateur-film',\n 'hudební videoklip': 'music-video',\n epizoda: 'episode',\n 'video kompilace': 'video-compilation',\n film: 'film'\n};\n\nexport const parseFilmType = (type: string): CSFDFilmTypes => {\n return filmTypeMap[type] || 'film';\n};\n\nexport const addProtocol = (url: string): string => {\n return url.startsWith('//') ? 'https:' + url : url;\n};\n\nexport const getDuration = (matches: RegExpMatchArray) => {\n return {\n sign: matches[1] === undefined ? '+' : '-',\n years: matches[2] === undefined ? 0 : matches[2],\n months: matches[3] === undefined ? 0 : matches[3],\n weeks: matches[4] === undefined ? 0 : matches[4],\n days: matches[5] === undefined ? 0 : matches[5],\n hours: matches[6] === undefined ? 0 : matches[6],\n minutes: matches[7] === undefined ? 0 : matches[7],\n seconds: matches[8] === undefined ? 0 : matches[8]\n };\n};\n\nexport const parseISO8601Duration = (iso: string): number => {\n const matches = iso.match(ISO8601_DURATION_REGEX);\n\n const duration = getDuration(matches);\n\n return +duration.hours * 60 + +duration.minutes;\n};\n\n/**\n * Parses a date string into a standardized YYYY-MM-DD format.\n * Supports:\n * - D.M.YYYY\n * - DD.MM.YYYY\n * - D. M. YYYY\n * - MM/DD/YYYY\n * - YYYY\n */\nexport const parseDate = (date: string): string | null => {\n if (!date) return null;\n\n // Clean the input\n const cleanDate = date.trim();\n\n // Try parsing DD.MM.YYYY or D.M.YYYY with optional spaces\n const dateMatch = cleanDate.match(/^(\\d{1,2})\\.\\s*(\\d{1,2})\\.\\s*(\\d{4})$/);\n if (dateMatch) {\n const day = dateMatch[1].padStart(2, '0');\n const month = dateMatch[2].padStart(2, '0');\n const year = dateMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing MM/DD/YYYY\n const slashMatch = cleanDate.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n if (slashMatch) {\n const month = slashMatch[1].padStart(2, '0');\n const day = slashMatch[2].padStart(2, '0');\n const year = slashMatch[3];\n return `${year}-${month}-${day}`;\n }\n\n // Try parsing YYYY\n const yearMatch = cleanDate.match(/^(\\d{4})$/);\n if (yearMatch) {\n return `${yearMatch[1]}-01-01`;\n }\n\n return null;\n};\n\n// Sleep in loop\nexport const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));\n"],"mappings":";AAGA,MAAM,oBAAoB;AAC1B,MAAM,yBACJ;AAEF,MAAa,kBAAkB,QAAwB;AACrD,KAAI,CAAC,IAAK,QAAO;CAEjB,MAAM,QAAQ,IAAI,MAAM,IAAI;AAK5B,QAAO,CAFQ,MADO,kBAAkB,KAAK,MAAM,GAAG,GACjB,IAAI,IACtB,MAAM,IAAI,CAAC,MAChB;;AAGhB,MAAa,sBAAsB,QAAwB;AACzD,KAAI,IAGF,QAAO,EAFQ,KAAK,MAAM,IAAI,CAAC,KACZ,MAAM,IAAI,CAAC,MAChB;KAEd,QAAO;;AAIX,MAAa,YAAY,QAAiC;AACxD,SAAQ,KAAR;EACE,KAAK,iBACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAa,cAAc,YAAyC;AAClE,SAAQ,SAAR;EACE,KAAK,YACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAM,cAA6C;CACjD,WAAW;CACX,OAAO;CACP,QAAQ;CACR,oBAAoB;CACpB,SAAS;CACT,OAAO;CACP,mBAAmB;CACnB,kBAAkB;CAClB,qBAAqB;CACrB,SAAS;CACT,mBAAmB;CACnB,MAAM;CACP;AAED,MAAa,iBAAiB,SAAgC;AAC5D,QAAO,YAAY,SAAS;;AAG9B,MAAa,eAAe,QAAwB;AAClD,QAAO,IAAI,WAAW,KAAK,GAAG,WAAW,MAAM;;AAGjD,MAAa,eAAe,YAA8B;AACxD,QAAO;EACL,MAAM,QAAQ,OAAO,SAAY,MAAM;EACvC,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,QAAQ,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC/C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,MAAM,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC7C,OAAO,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAC9C,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EAChD,SAAS,QAAQ,OAAO,SAAY,IAAI,QAAQ;EACjD;;AAGH,MAAa,wBAAwB,QAAwB;CAG3D,MAAM,WAAW,YAFD,IAAI,MAAM,uBAAuB,CAEZ;AAErC,QAAO,CAAC,SAAS,QAAQ,KAAK,CAAC,SAAS;;;;;;;;;;;AAY1C,MAAa,aAAa,SAAgC;AACxD,KAAI,CAAC,KAAM,QAAO;CAGlB,MAAM,YAAY,KAAK,MAAM;CAG7B,MAAM,YAAY,UAAU,MAAM,wCAAwC;AAC1E,KAAI,WAAW;EACb,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI;EACzC,MAAM,QAAQ,UAAU,GAAG,SAAS,GAAG,IAAI;AAE3C,SAAO,GADM,UAAU,GACR,GAAG,MAAM,GAAG;;CAI7B,MAAM,aAAa,UAAU,MAAM,kCAAkC;AACrE,KAAI,YAAY;EACd,MAAM,QAAQ,WAAW,GAAG,SAAS,GAAG,IAAI;EAC5C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI;AAE1C,SAAO,GADM,WAAW,GACT,GAAG,MAAM,GAAG;;CAI7B,MAAM,YAAY,UAAU,MAAM,YAAY;AAC9C,KAAI,UACF,QAAO,GAAG,UAAU,GAAG;AAGzB,QAAO;;AAIT,MAAa,SAAS,OAAe,IAAI,SAAS,QAAQ,WAAW,KAAK,GAAG,CAAC"}
@@ -57,6 +57,25 @@ const CREATOR_LABELS = {
57
57
  const getLocalizedCreatorLabel = (language, key) => {
58
58
  return (CREATOR_LABELS[language || "cs"] || CREATOR_LABELS["cs"])[key];
59
59
  };
60
+ const getSeriesAndSeasonTitle = (el) => {
61
+ const titleElement = el.querySelector("h1");
62
+ if (!titleElement) return {
63
+ seriesName: null,
64
+ seasonName: null
65
+ };
66
+ const fullText = titleElement.innerText.trim();
67
+ if (fullText.includes(" - ")) {
68
+ const [seriesName, seasonName] = fullText.split(" - ").map((part) => part.trim());
69
+ return {
70
+ seriesName,
71
+ seasonName
72
+ };
73
+ }
74
+ return {
75
+ seriesName: fullText,
76
+ seasonName: null
77
+ };
78
+ };
60
79
  const getMovieTitle = (el) => {
61
80
  return el.querySelector("h1").innerText.split(`(`)[0].trim();
62
81
  };
@@ -177,6 +196,65 @@ const getMovieCreators = (el, options) => {
177
196
  }
178
197
  return creators;
179
198
  };
199
+ const getSeasonsOrEpisodes = (el, serie) => {
200
+ const childrenList = el.querySelector(".film-episodes-list");
201
+ if (!childrenList) return null;
202
+ const childrenNodes = childrenList.querySelectorAll(".film-title");
203
+ if (!childrenNodes?.length) return [];
204
+ return childrenNodes.map((season) => {
205
+ const nameContainer = season.querySelector(".film-title-name");
206
+ const infoContainer = season.querySelector(".info");
207
+ const href = nameContainer?.getAttribute("href");
208
+ const url = href ? href.startsWith("/") ? `https://www.csfd.cz${href}` : href : null;
209
+ return {
210
+ id: require_global_helper.parseLastIdFromUrl(href || ""),
211
+ title: nameContainer?.textContent?.trim() || null,
212
+ url,
213
+ info: infoContainer?.textContent?.replace(/[{()}]/g, "").trim() || null
214
+ };
215
+ });
216
+ };
217
+ const getEpisodeCode = (el) => {
218
+ const filmHeaderName = el.querySelector(".film-header-name h1");
219
+ if (!filmHeaderName) return null;
220
+ const match = (filmHeaderName.textContent?.trim() || "").match(/\(([^)]+)\)/);
221
+ return match ? match[1] : null;
222
+ };
223
+ const detectSeasonOrEpisodeListType = (el) => {
224
+ const headerText = el.querySelector(".box-header h3")?.innerText.trim() ?? "";
225
+ if (headerText.includes("Série")) return "seasons";
226
+ if (headerText.startsWith("Epizody")) return "episodes";
227
+ return null;
228
+ };
229
+ const getSeasonOrEpisodeParent = (el, serie) => {
230
+ let parents = el.querySelectorAll(".film-header h2 a");
231
+ if (parents.length === 0) parents = el.querySelectorAll(".film-header h1 a");
232
+ if (parents.length === 0) {
233
+ if (!serie) return null;
234
+ return {
235
+ series: serie,
236
+ season: null
237
+ };
238
+ }
239
+ const [parentSeries, parentSeason] = parents;
240
+ const seriesId = require_global_helper.parseIdFromUrl(parentSeries?.getAttribute("href"));
241
+ const seasonId = require_global_helper.parseLastIdFromUrl(parentSeason?.getAttribute("href") || "");
242
+ const seriesTitle = parentSeries?.textContent?.trim() || null;
243
+ const seasonTitle = parentSeason?.textContent?.trim() || null;
244
+ const series = seriesId && seriesTitle ? {
245
+ id: seriesId,
246
+ title: seriesTitle
247
+ } : null;
248
+ const season = seasonId && seasonTitle ? {
249
+ id: seasonId,
250
+ title: seasonTitle
251
+ } : null;
252
+ if (!series && !season) return null;
253
+ return {
254
+ series,
255
+ season
256
+ };
257
+ };
180
258
  const getMovieType = (el) => {
181
259
  return require_global_helper.parseFilmType(el.querySelector(".film-header-name .type")?.innerText?.replace(/[{()}]/g, "") || "film");
182
260
  };
@@ -226,6 +304,8 @@ const getMovieTags = (el) => {
226
304
  };
227
305
 
228
306
  //#endregion
307
+ exports.detectSeasonOrEpisodeListType = detectSeasonOrEpisodeListType;
308
+ exports.getEpisodeCode = getEpisodeCode;
229
309
  exports.getMovieBoxMovies = getMovieBoxMovies;
230
310
  exports.getMovieColorRating = getMovieColorRating;
231
311
  exports.getMovieCreators = getMovieCreators;
@@ -245,4 +325,7 @@ exports.getMovieTrivia = getMovieTrivia;
245
325
  exports.getMovieType = getMovieType;
246
326
  exports.getMovieVods = getMovieVods;
247
327
  exports.getMovieYear = getMovieYear;
328
+ exports.getSeasonOrEpisodeParent = getSeasonOrEpisodeParent;
329
+ exports.getSeasonsOrEpisodes = getSeasonsOrEpisodes;
330
+ exports.getSeriesAndSeasonTitle = getSeriesAndSeasonTitle;
248
331
  //# sourceMappingURL=movie.helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"movie.helper.js","names":["getColor","parseISO8601Duration","addProtocol","parseIdFromUrl","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 CSFDPremiere,\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} 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 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 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.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,4 +1,4 @@
1
- import { addProtocol, getColor, parseDate, parseFilmType, parseISO8601Duration, parseIdFromUrl } from "./global.helper.mjs";
1
+ import { addProtocol, getColor, parseDate, parseFilmType, parseISO8601Duration, parseIdFromUrl, parseLastIdFromUrl } from "./global.helper.mjs";
2
2
 
3
3
  //#region src/helpers/movie.helper.ts
4
4
  const CREATOR_LABELS = {
@@ -57,6 +57,25 @@ const CREATOR_LABELS = {
57
57
  const getLocalizedCreatorLabel = (language, key) => {
58
58
  return (CREATOR_LABELS[language || "cs"] || CREATOR_LABELS["cs"])[key];
59
59
  };
60
+ const getSeriesAndSeasonTitle = (el) => {
61
+ const titleElement = el.querySelector("h1");
62
+ if (!titleElement) return {
63
+ seriesName: null,
64
+ seasonName: null
65
+ };
66
+ const fullText = titleElement.innerText.trim();
67
+ if (fullText.includes(" - ")) {
68
+ const [seriesName, seasonName] = fullText.split(" - ").map((part) => part.trim());
69
+ return {
70
+ seriesName,
71
+ seasonName
72
+ };
73
+ }
74
+ return {
75
+ seriesName: fullText,
76
+ seasonName: null
77
+ };
78
+ };
60
79
  const getMovieTitle = (el) => {
61
80
  return el.querySelector("h1").innerText.split(`(`)[0].trim();
62
81
  };
@@ -177,6 +196,65 @@ const getMovieCreators = (el, options) => {
177
196
  }
178
197
  return creators;
179
198
  };
199
+ const getSeasonsOrEpisodes = (el, serie) => {
200
+ const childrenList = el.querySelector(".film-episodes-list");
201
+ if (!childrenList) return null;
202
+ const childrenNodes = childrenList.querySelectorAll(".film-title");
203
+ if (!childrenNodes?.length) return [];
204
+ return childrenNodes.map((season) => {
205
+ const nameContainer = season.querySelector(".film-title-name");
206
+ const infoContainer = season.querySelector(".info");
207
+ const href = nameContainer?.getAttribute("href");
208
+ const url = href ? href.startsWith("/") ? `https://www.csfd.cz${href}` : href : null;
209
+ return {
210
+ id: parseLastIdFromUrl(href || ""),
211
+ title: nameContainer?.textContent?.trim() || null,
212
+ url,
213
+ info: infoContainer?.textContent?.replace(/[{()}]/g, "").trim() || null
214
+ };
215
+ });
216
+ };
217
+ const getEpisodeCode = (el) => {
218
+ const filmHeaderName = el.querySelector(".film-header-name h1");
219
+ if (!filmHeaderName) return null;
220
+ const match = (filmHeaderName.textContent?.trim() || "").match(/\(([^)]+)\)/);
221
+ return match ? match[1] : null;
222
+ };
223
+ const detectSeasonOrEpisodeListType = (el) => {
224
+ const headerText = el.querySelector(".box-header h3")?.innerText.trim() ?? "";
225
+ if (headerText.includes("Série")) return "seasons";
226
+ if (headerText.startsWith("Epizody")) return "episodes";
227
+ return null;
228
+ };
229
+ const getSeasonOrEpisodeParent = (el, serie) => {
230
+ let parents = el.querySelectorAll(".film-header h2 a");
231
+ if (parents.length === 0) parents = el.querySelectorAll(".film-header h1 a");
232
+ if (parents.length === 0) {
233
+ if (!serie) return null;
234
+ return {
235
+ series: serie,
236
+ season: null
237
+ };
238
+ }
239
+ const [parentSeries, parentSeason] = parents;
240
+ const seriesId = parseIdFromUrl(parentSeries?.getAttribute("href"));
241
+ const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute("href") || "");
242
+ const seriesTitle = parentSeries?.textContent?.trim() || null;
243
+ const seasonTitle = parentSeason?.textContent?.trim() || null;
244
+ const series = seriesId && seriesTitle ? {
245
+ id: seriesId,
246
+ title: seriesTitle
247
+ } : null;
248
+ const season = seasonId && seasonTitle ? {
249
+ id: seasonId,
250
+ title: seasonTitle
251
+ } : null;
252
+ if (!series && !season) return null;
253
+ return {
254
+ series,
255
+ season
256
+ };
257
+ };
180
258
  const getMovieType = (el) => {
181
259
  return parseFilmType(el.querySelector(".film-header-name .type")?.innerText?.replace(/[{()}]/g, "") || "film");
182
260
  };
@@ -226,5 +304,5 @@ const getMovieTags = (el) => {
226
304
  };
227
305
 
228
306
  //#endregion
229
- export { getMovieBoxMovies, getMovieColorRating, getMovieCreators, getMovieDescriptions, getMovieDuration, getMovieGenres, getMovieOrigins, getMoviePoster, getMoviePremieres, getMovieRandomPhoto, getMovieRating, getMovieRatingCount, getMovieTags, getMovieTitle, getMovieTitlesOther, getMovieTrivia, getMovieType, getMovieVods, getMovieYear };
307
+ export { detectSeasonOrEpisodeListType, getEpisodeCode, getMovieBoxMovies, getMovieColorRating, getMovieCreators, getMovieDescriptions, getMovieDuration, getMovieGenres, getMovieOrigins, getMoviePoster, getMoviePremieres, getMovieRandomPhoto, getMovieRating, getMovieRatingCount, getMovieTags, getMovieTitle, getMovieTitlesOther, getMovieTrivia, getMovieType, getMovieVods, getMovieYear, getSeasonOrEpisodeParent, getSeasonsOrEpisodes, getSeriesAndSeasonTitle };
230
308
  //# sourceMappingURL=movie.helper.mjs.map
@@ -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 CSFDPremiere,\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} 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 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 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.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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"}
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CSFDColorRating, CSFDFilmTypes, CSFDScreening, CSFDStars } from "./dto/global.mjs";
2
- import { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd } from "./dto/movie.mjs";
2
+ import { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDSeriesChild, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd } from "./dto/movie.mjs";
3
3
  import { CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod } from "./dto/cinema.mjs";
4
4
  import { CSFDCreator, CSFDCreatorScreening } from "./dto/creator.mjs";
5
5
  import { CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser } from "./dto/search.mjs";
@@ -36,5 +36,5 @@ declare class Csfd {
36
36
  }
37
37
  declare const csfd: Csfd;
38
38
  //#endregion
39
- export { CSFDBoxContent, CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod, CSFDColorRating, CSFDColors, CSFDCreator, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreatorScreening, CSFDCreators, CSFDFilmTypes, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDScreening, CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser, CSFDStars, CSFDTitlesOther, CSFDUserRatingConfig, CSFDUserRatings, CSFDVod, CSFDVodService, Csfd, MovieJsonLd, csfd };
39
+ export { CSFDBoxContent, CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod, CSFDColorRating, CSFDColors, CSFDCreator, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreatorScreening, CSFDCreators, CSFDFilmTypes, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDScreening, CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser, CSFDSeriesChild, CSFDStars, CSFDTitlesOther, CSFDUserRatingConfig, CSFDUserRatings, CSFDVod, CSFDVodService, Csfd, MovieJsonLd, csfd };
40
40
  //# sourceMappingURL=index.d.mts.map
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CSFDColorRating, CSFDFilmTypes, CSFDScreening, CSFDStars } from "./dto/global.js";
2
- import { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd } from "./dto/movie.js";
2
+ import { CSFDBoxContent, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreators, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDSeriesChild, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd } from "./dto/movie.js";
3
3
  import { CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod } from "./dto/cinema.js";
4
4
  import { CSFDCreator, CSFDCreatorScreening } from "./dto/creator.js";
5
5
  import { CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser } from "./dto/search.js";
@@ -36,5 +36,5 @@ declare class Csfd {
36
36
  }
37
37
  declare const csfd: Csfd;
38
38
  //#endregion
39
- export { CSFDBoxContent, CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod, CSFDColorRating, CSFDColors, CSFDCreator, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreatorScreening, CSFDCreators, CSFDFilmTypes, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDPremiere, CSFDScreening, CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser, CSFDStars, CSFDTitlesOther, CSFDUserRatingConfig, CSFDUserRatings, CSFDVod, CSFDVodService, Csfd, MovieJsonLd, csfd };
39
+ export { CSFDBoxContent, CSFDCinema, CSFDCinemaGroupedFilmsByDate, CSFDCinemaMeta, CSFDCinemaMovie, CSFDCinemaPeriod, CSFDColorRating, CSFDColors, CSFDCreator, CSFDCreatorGroups, CSFDCreatorGroupsEnglish, CSFDCreatorGroupsSlovak, CSFDCreatorScreening, CSFDCreators, CSFDFilmTypes, CSFDGenres, CSFDMovie, CSFDMovieCreator, CSFDMovieListItem, CSFDParent, CSFDPremiere, CSFDScreening, CSFDSearch, CSFDSearchCreator, CSFDSearchCreators, CSFDSearchMovie, CSFDSearchUser, CSFDSeriesChild, CSFDStars, CSFDTitlesOther, CSFDUserRatingConfig, CSFDUserRatings, CSFDVod, CSFDVodService, Csfd, MovieJsonLd, csfd };
40
40
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-csfd-api",
3
- "version": "5.0.0-next.1",
3
+ "version": "5.0.0-next.3",
4
4
  "description": "ČSFD API in JavaScript. Amazing NPM library for scrapping csfd.cz :)",
5
5
  "author": "BART! <bart@bartweb.cz>",
6
6
  "publishConfig": {
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.0.0-next.1";
4
+ var version = "5.0.0-next.3";
5
5
  var homepage = "https://github.com/bartholomej/node-csfd-api#readme";
6
6
 
7
7
  //#endregion
@@ -22,14 +22,18 @@ var MovieScraper = class {
22
22
  return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);
23
23
  }
24
24
  buildMovie(movieId, el, asideEl, pageClasses, jsonLd, options) {
25
+ const type = require_movie_helper.getMovieType(el);
26
+ const { seriesName = null, seasonName = null } = type === "season" ? require_movie_helper.getSeriesAndSeasonTitle(el) : {};
27
+ const seasonOrEpisodeListType = require_movie_helper.detectSeasonOrEpisodeListType(el);
28
+ const title = type === "season" && seriesName ? seriesName : require_movie_helper.getMovieTitle(el);
25
29
  return {
26
30
  id: movieId,
27
- title: require_movie_helper.getMovieTitle(el),
31
+ title,
28
32
  year: require_movie_helper.getMovieYear(jsonLd),
29
33
  duration: require_movie_helper.getMovieDuration(jsonLd, el),
30
34
  descriptions: require_movie_helper.getMovieDescriptions(el),
31
35
  genres: require_movie_helper.getMovieGenres(el),
32
- type: require_movie_helper.getMovieType(el),
36
+ type,
33
37
  url: require_vars.movieUrl(movieId, { language: options?.language }),
34
38
  origins: require_movie_helper.getMovieOrigins(el),
35
39
  colorRating: require_movie_helper.getMovieColorRating(pageClasses),
@@ -44,7 +48,15 @@ var MovieScraper = class {
44
48
  tags: require_movie_helper.getMovieTags(asideEl),
45
49
  premieres: require_movie_helper.getMoviePremieres(asideEl),
46
50
  related: require_movie_helper.getMovieBoxMovies(asideEl, "Související"),
47
- similar: require_movie_helper.getMovieBoxMovies(asideEl, "Podobné")
51
+ similar: require_movie_helper.getMovieBoxMovies(asideEl, "Podobné"),
52
+ seasons: seasonOrEpisodeListType === "seasons" ? require_movie_helper.getSeasonsOrEpisodes(el) : null,
53
+ episodes: seasonOrEpisodeListType === "episodes" ? require_movie_helper.getSeasonsOrEpisodes(el) : null,
54
+ parent: type === "series" ? null : require_movie_helper.getSeasonOrEpisodeParent(el, {
55
+ id: movieId,
56
+ title
57
+ }),
58
+ episodeCode: type === "episode" ? require_movie_helper.getEpisodeCode(el) : null,
59
+ seasonName
48
60
  };
49
61
  }
50
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"movie.service.js","names":["fetchPage","movieUrl","getMovieTitle","getMovieYear","getMovieDuration","getMovieDescriptions","getMovieGenres","getMovieType","getMovieOrigins","getMovieColorRating","getMovieRating","getMovieRatingCount","getMovieTitlesOther","getMoviePoster","getMovieRandomPhoto","getMovieTrivia","getMovieCreators","getMovieVods","getMovieTags","getMoviePremieres","getMovieBoxMovies"],"sources":["../../src/services/movie.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovie, MovieJsonLd } from '../dto/movie';\nimport { fetchPage } from '../fetchers';\nimport {\n getMovieBoxMovies,\n getMovieColorRating,\n getMovieCreators,\n getMovieDescriptions,\n getMovieDuration,\n getMovieGenres,\n getMovieOrigins,\n getMoviePoster,\n getMoviePremieres,\n getMovieRandomPhoto,\n getMovieRating,\n getMovieRatingCount,\n getMovieTags,\n getMovieTitle,\n getMovieTitlesOther,\n getMovieTrivia,\n getMovieType,\n getMovieVods,\n getMovieYear\n} from '../helpers/movie.helper';\nimport { CSFDOptions } from '../types';\nimport { movieUrl } from '../vars';\n\nexport class MovieScraper {\n public async movie(movieId: number, options?: CSFDOptions): Promise<CSFDMovie> {\n const id = Number(movieId);\n if (isNaN(id)) {\n throw new Error('node-csfd-api: movieId must be a valid number');\n }\n const url = movieUrl(id, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const movieHtml = parse(response);\n\n const pageClasses = movieHtml.querySelector('.page-content').classNames.split(' ');\n const asideNode = movieHtml.querySelector('.aside-movie-profile');\n const movieNode = movieHtml.querySelector('.main-movie-profile');\n const jsonLdString = movieHtml.querySelector('script[type=\"application/ld+json\"]').innerText;\n let jsonLd: MovieJsonLd | null = null;\n try {\n jsonLd = JSON.parse(jsonLdString);\n } catch (e) {\n console.error('node-csfd-api: Error parsing JSON-LD', e);\n }\n return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);\n }\n\n private buildMovie(\n movieId: number,\n el: HTMLElement,\n asideEl: HTMLElement,\n pageClasses: string[],\n jsonLd: MovieJsonLd | null,\n options: CSFDOptions\n ): CSFDMovie {\n return {\n id: movieId,\n title: getMovieTitle(el),\n year: getMovieYear(jsonLd),\n duration: getMovieDuration(jsonLd, el),\n descriptions: getMovieDescriptions(el),\n genres: getMovieGenres(el),\n type: getMovieType(el) as CSFDFilmTypes,\n url: movieUrl(movieId, { language: options?.language }),\n origins: getMovieOrigins(el),\n colorRating: getMovieColorRating(pageClasses),\n rating: getMovieRating(asideEl),\n ratingCount: getMovieRatingCount(asideEl),\n titlesOther: getMovieTitlesOther(el),\n poster: getMoviePoster(el),\n photo: getMovieRandomPhoto(el),\n trivia: getMovieTrivia(el),\n creators: getMovieCreators(el, options),\n vod: getMovieVods(asideEl),\n tags: getMovieTags(asideEl),\n premieres: getMoviePremieres(asideEl),\n related: getMovieBoxMovies(asideEl, 'Související'),\n similar: getMovieBoxMovies(asideEl, 'Podobné')\n };\n }\n}\n"],"mappings":";;;;;;AA4BA,IAAa,eAAb,MAA0B;CACxB,MAAa,MAAM,SAAiB,SAA2C;EAC7E,MAAM,KAAK,OAAO,QAAQ;AAC1B,MAAI,MAAM,GAAG,CACX,OAAM,IAAI,MAAM,gDAAgD;EAKlE,MAAM,wCAFW,MAAMA,wBADXC,sBAAS,IAAI,EAAE,UAAU,SAAS,UAAU,CAAC,EACnB,EAAE,GAAG,SAAS,SAAS,CAAC,CAE7B;EAEjC,MAAM,cAAc,UAAU,cAAc,gBAAgB,CAAC,WAAW,MAAM,IAAI;EAClF,MAAM,YAAY,UAAU,cAAc,uBAAuB;EACjE,MAAM,YAAY,UAAU,cAAc,sBAAsB;EAChE,MAAM,eAAe,UAAU,cAAc,uCAAqC,CAAC;EACnF,IAAI,SAA6B;AACjC,MAAI;AACF,YAAS,KAAK,MAAM,aAAa;WAC1B,GAAG;AACV,WAAQ,MAAM,wCAAwC,EAAE;;AAE1D,SAAO,KAAK,WAAW,CAAC,SAAS,WAAW,WAAW,aAAa,QAAQ,QAAQ;;CAGtF,AAAQ,WACN,SACA,IACA,SACA,aACA,QACA,SACW;AACX,SAAO;GACL,IAAI;GACJ,OAAOC,mCAAc,GAAG;GACxB,MAAMC,kCAAa,OAAO;GAC1B,UAAUC,sCAAiB,QAAQ,GAAG;GACtC,cAAcC,0CAAqB,GAAG;GACtC,QAAQC,oCAAe,GAAG;GAC1B,MAAMC,kCAAa,GAAG;GACtB,KAAKN,sBAAS,SAAS,EAAE,UAAU,SAAS,UAAU,CAAC;GACvD,SAASO,qCAAgB,GAAG;GAC5B,aAAaC,yCAAoB,YAAY;GAC7C,QAAQC,oCAAe,QAAQ;GAC/B,aAAaC,yCAAoB,QAAQ;GACzC,aAAaC,yCAAoB,GAAG;GACpC,QAAQC,oCAAe,GAAG;GAC1B,OAAOC,yCAAoB,GAAG;GAC9B,QAAQC,oCAAe,GAAG;GAC1B,UAAUC,sCAAiB,IAAI,QAAQ;GACvC,KAAKC,kCAAa,QAAQ;GAC1B,MAAMC,kCAAa,QAAQ;GAC3B,WAAWC,uCAAkB,QAAQ;GACrC,SAASC,uCAAkB,SAAS,cAAc;GAClD,SAASA,uCAAkB,SAAS,UAAU;GAC/C"}
1
+ {"version":3,"file":"movie.service.js","names":["fetchPage","movieUrl","getMovieType","getSeriesAndSeasonTitle","detectSeasonOrEpisodeListType","getMovieTitle","getMovieYear","getMovieDuration","getMovieDescriptions","getMovieGenres","getMovieOrigins","getMovieColorRating","getMovieRating","getMovieRatingCount","getMovieTitlesOther","getMoviePoster","getMovieRandomPhoto","getMovieTrivia","getMovieCreators","getMovieVods","getMovieTags","getMoviePremieres","getMovieBoxMovies","getSeasonsOrEpisodes","getSeasonOrEpisodeParent","getEpisodeCode"],"sources":["../../src/services/movie.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovie, MovieJsonLd } from '../dto/movie';\nimport { fetchPage } from '../fetchers';\nimport {\n detectSeasonOrEpisodeListType,\n getEpisodeCode,\n getMovieBoxMovies,\n getMovieColorRating,\n getMovieCreators,\n getMovieDescriptions,\n getMovieDuration,\n getMovieGenres,\n getMovieOrigins,\n getMoviePoster,\n getMoviePremieres,\n getMovieRandomPhoto,\n getMovieRating,\n getMovieRatingCount,\n getMovieTags,\n getMovieTitle,\n getMovieTitlesOther,\n getMovieTrivia,\n getMovieType,\n getMovieVods,\n getMovieYear,\n getSeasonOrEpisodeParent,\n getSeasonsOrEpisodes,\n getSeriesAndSeasonTitle\n} from '../helpers/movie.helper';\nimport { CSFDOptions } from '../types';\nimport { movieUrl } from '../vars';\n\nexport class MovieScraper {\n public async movie(movieId: number, options?: CSFDOptions): Promise<CSFDMovie> {\n const id = Number(movieId);\n if (isNaN(id)) {\n throw new Error('node-csfd-api: movieId must be a valid number');\n }\n const url = movieUrl(id, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const movieHtml = parse(response);\n\n const pageClasses = movieHtml.querySelector('.page-content').classNames.split(' ');\n const asideNode = movieHtml.querySelector('.aside-movie-profile');\n const movieNode = movieHtml.querySelector('.main-movie-profile');\n const jsonLdString = movieHtml.querySelector('script[type=\"application/ld+json\"]').innerText;\n let jsonLd: MovieJsonLd | null = null;\n try {\n jsonLd = JSON.parse(jsonLdString);\n } catch (e) {\n console.error('node-csfd-api: Error parsing JSON-LD', e);\n }\n return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);\n }\n\n private buildMovie(\n movieId: number,\n el: HTMLElement,\n asideEl: HTMLElement,\n pageClasses: string[],\n jsonLd: MovieJsonLd | null,\n options: CSFDOptions\n ) {\n const type = getMovieType(el) as CSFDFilmTypes;\n const { seriesName = null, seasonName = null } =\n type === 'season' ? getSeriesAndSeasonTitle(el) : {};\n const seasonOrEpisodeListType = detectSeasonOrEpisodeListType(el);\n\n const title = type === 'season' && seriesName ? seriesName : getMovieTitle(el);\n return {\n id: movieId,\n title,\n year: getMovieYear(jsonLd),\n duration: getMovieDuration(jsonLd, el),\n descriptions: getMovieDescriptions(el),\n genres: getMovieGenres(el),\n type,\n url: movieUrl(movieId, { language: options?.language }),\n origins: getMovieOrigins(el),\n colorRating: getMovieColorRating(pageClasses),\n rating: getMovieRating(asideEl),\n ratingCount: getMovieRatingCount(asideEl),\n titlesOther: getMovieTitlesOther(el),\n poster: getMoviePoster(el),\n photo: getMovieRandomPhoto(el),\n trivia: getMovieTrivia(el),\n creators: getMovieCreators(el, options),\n vod: getMovieVods(asideEl),\n tags: getMovieTags(asideEl),\n premieres: getMoviePremieres(asideEl),\n related: getMovieBoxMovies(asideEl, 'Související'),\n similar: getMovieBoxMovies(asideEl, 'Podobné'),\n seasons: seasonOrEpisodeListType === 'seasons' ? getSeasonsOrEpisodes(el) : null,\n episodes: seasonOrEpisodeListType === 'episodes' ? getSeasonsOrEpisodes(el) : null,\n parent: type === 'series' ? null : getSeasonOrEpisodeParent(el, { id: movieId, title }),\n episodeCode: type === 'episode' ? getEpisodeCode(el) : null,\n seasonName\n };\n }\n}\n"],"mappings":";;;;;;AAiCA,IAAa,eAAb,MAA0B;CACxB,MAAa,MAAM,SAAiB,SAA2C;EAC7E,MAAM,KAAK,OAAO,QAAQ;AAC1B,MAAI,MAAM,GAAG,CACX,OAAM,IAAI,MAAM,gDAAgD;EAKlE,MAAM,wCAFW,MAAMA,wBADXC,sBAAS,IAAI,EAAE,UAAU,SAAS,UAAU,CAAC,EACnB,EAAE,GAAG,SAAS,SAAS,CAAC,CAE7B;EAEjC,MAAM,cAAc,UAAU,cAAc,gBAAgB,CAAC,WAAW,MAAM,IAAI;EAClF,MAAM,YAAY,UAAU,cAAc,uBAAuB;EACjE,MAAM,YAAY,UAAU,cAAc,sBAAsB;EAChE,MAAM,eAAe,UAAU,cAAc,uCAAqC,CAAC;EACnF,IAAI,SAA6B;AACjC,MAAI;AACF,YAAS,KAAK,MAAM,aAAa;WAC1B,GAAG;AACV,WAAQ,MAAM,wCAAwC,EAAE;;AAE1D,SAAO,KAAK,WAAW,CAAC,SAAS,WAAW,WAAW,aAAa,QAAQ,QAAQ;;CAGtF,AAAQ,WACN,SACA,IACA,SACA,aACA,QACA,SACA;EACA,MAAM,OAAOC,kCAAa,GAAG;EAC7B,MAAM,EAAE,aAAa,MAAM,aAAa,SACtC,SAAS,WAAWC,6CAAwB,GAAG,GAAG,EAAE;EACtD,MAAM,0BAA0BC,mDAA8B,GAAG;EAEjE,MAAM,QAAQ,SAAS,YAAY,aAAa,aAAaC,mCAAc,GAAG;AAC9E,SAAO;GACL,IAAI;GACJ;GACA,MAAMC,kCAAa,OAAO;GAC1B,UAAUC,sCAAiB,QAAQ,GAAG;GACtC,cAAcC,0CAAqB,GAAG;GACtC,QAAQC,oCAAe,GAAG;GAC1B;GACA,KAAKR,sBAAS,SAAS,EAAE,UAAU,SAAS,UAAU,CAAC;GACvD,SAASS,qCAAgB,GAAG;GAC5B,aAAaC,yCAAoB,YAAY;GAC7C,QAAQC,oCAAe,QAAQ;GAC/B,aAAaC,yCAAoB,QAAQ;GACzC,aAAaC,yCAAoB,GAAG;GACpC,QAAQC,oCAAe,GAAG;GAC1B,OAAOC,yCAAoB,GAAG;GAC9B,QAAQC,oCAAe,GAAG;GAC1B,UAAUC,sCAAiB,IAAI,QAAQ;GACvC,KAAKC,kCAAa,QAAQ;GAC1B,MAAMC,kCAAa,QAAQ;GAC3B,WAAWC,uCAAkB,QAAQ;GACrC,SAASC,uCAAkB,SAAS,cAAc;GAClD,SAASA,uCAAkB,SAAS,UAAU;GAC9C,SAAS,4BAA4B,YAAYC,0CAAqB,GAAG,GAAG;GAC5E,UAAU,4BAA4B,aAAaA,0CAAqB,GAAG,GAAG;GAC9E,QAAQ,SAAS,WAAW,OAAOC,8CAAyB,IAAI;IAAE,IAAI;IAAS;IAAO,CAAC;GACvF,aAAa,SAAS,YAAYC,oCAAe,GAAG,GAAG;GACvD;GACD"}
@@ -1,6 +1,6 @@
1
1
  import { fetchPage } from "../fetchers/index.mjs";
2
2
  import { movieUrl } from "../vars.mjs";
3
- import { getMovieBoxMovies, getMovieColorRating, getMovieCreators, getMovieDescriptions, getMovieDuration, getMovieGenres, getMovieOrigins, getMoviePoster, getMoviePremieres, getMovieRandomPhoto, getMovieRating, getMovieRatingCount, getMovieTags, getMovieTitle, getMovieTitlesOther, getMovieTrivia, getMovieType, getMovieVods, getMovieYear } from "../helpers/movie.helper.mjs";
3
+ import { detectSeasonOrEpisodeListType, getEpisodeCode, getMovieBoxMovies, getMovieColorRating, getMovieCreators, getMovieDescriptions, getMovieDuration, getMovieGenres, getMovieOrigins, getMoviePoster, getMoviePremieres, getMovieRandomPhoto, getMovieRating, getMovieRatingCount, getMovieTags, getMovieTitle, getMovieTitlesOther, getMovieTrivia, getMovieType, getMovieVods, getMovieYear, getSeasonOrEpisodeParent, getSeasonsOrEpisodes, getSeriesAndSeasonTitle } from "../helpers/movie.helper.mjs";
4
4
  import { parse } from "node-html-parser";
5
5
 
6
6
  //#region src/services/movie.service.ts
@@ -22,14 +22,18 @@ var MovieScraper = class {
22
22
  return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);
23
23
  }
24
24
  buildMovie(movieId, el, asideEl, pageClasses, jsonLd, options) {
25
+ const type = getMovieType(el);
26
+ const { seriesName = null, seasonName = null } = type === "season" ? getSeriesAndSeasonTitle(el) : {};
27
+ const seasonOrEpisodeListType = detectSeasonOrEpisodeListType(el);
28
+ const title = type === "season" && seriesName ? seriesName : getMovieTitle(el);
25
29
  return {
26
30
  id: movieId,
27
- title: getMovieTitle(el),
31
+ title,
28
32
  year: getMovieYear(jsonLd),
29
33
  duration: getMovieDuration(jsonLd, el),
30
34
  descriptions: getMovieDescriptions(el),
31
35
  genres: getMovieGenres(el),
32
- type: getMovieType(el),
36
+ type,
33
37
  url: movieUrl(movieId, { language: options?.language }),
34
38
  origins: getMovieOrigins(el),
35
39
  colorRating: getMovieColorRating(pageClasses),
@@ -44,7 +48,15 @@ var MovieScraper = class {
44
48
  tags: getMovieTags(asideEl),
45
49
  premieres: getMoviePremieres(asideEl),
46
50
  related: getMovieBoxMovies(asideEl, "Související"),
47
- similar: getMovieBoxMovies(asideEl, "Podobné")
51
+ similar: getMovieBoxMovies(asideEl, "Podobné"),
52
+ seasons: seasonOrEpisodeListType === "seasons" ? getSeasonsOrEpisodes(el) : null,
53
+ episodes: seasonOrEpisodeListType === "episodes" ? getSeasonsOrEpisodes(el) : null,
54
+ parent: type === "series" ? null : getSeasonOrEpisodeParent(el, {
55
+ id: movieId,
56
+ title
57
+ }),
58
+ episodeCode: type === "episode" ? getEpisodeCode(el) : null,
59
+ seasonName
48
60
  };
49
61
  }
50
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"movie.service.mjs","names":[],"sources":["../../src/services/movie.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovie, MovieJsonLd } from '../dto/movie';\nimport { fetchPage } from '../fetchers';\nimport {\n getMovieBoxMovies,\n getMovieColorRating,\n getMovieCreators,\n getMovieDescriptions,\n getMovieDuration,\n getMovieGenres,\n getMovieOrigins,\n getMoviePoster,\n getMoviePremieres,\n getMovieRandomPhoto,\n getMovieRating,\n getMovieRatingCount,\n getMovieTags,\n getMovieTitle,\n getMovieTitlesOther,\n getMovieTrivia,\n getMovieType,\n getMovieVods,\n getMovieYear\n} from '../helpers/movie.helper';\nimport { CSFDOptions } from '../types';\nimport { movieUrl } from '../vars';\n\nexport class MovieScraper {\n public async movie(movieId: number, options?: CSFDOptions): Promise<CSFDMovie> {\n const id = Number(movieId);\n if (isNaN(id)) {\n throw new Error('node-csfd-api: movieId must be a valid number');\n }\n const url = movieUrl(id, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const movieHtml = parse(response);\n\n const pageClasses = movieHtml.querySelector('.page-content').classNames.split(' ');\n const asideNode = movieHtml.querySelector('.aside-movie-profile');\n const movieNode = movieHtml.querySelector('.main-movie-profile');\n const jsonLdString = movieHtml.querySelector('script[type=\"application/ld+json\"]').innerText;\n let jsonLd: MovieJsonLd | null = null;\n try {\n jsonLd = JSON.parse(jsonLdString);\n } catch (e) {\n console.error('node-csfd-api: Error parsing JSON-LD', e);\n }\n return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);\n }\n\n private buildMovie(\n movieId: number,\n el: HTMLElement,\n asideEl: HTMLElement,\n pageClasses: string[],\n jsonLd: MovieJsonLd | null,\n options: CSFDOptions\n ): CSFDMovie {\n return {\n id: movieId,\n title: getMovieTitle(el),\n year: getMovieYear(jsonLd),\n duration: getMovieDuration(jsonLd, el),\n descriptions: getMovieDescriptions(el),\n genres: getMovieGenres(el),\n type: getMovieType(el) as CSFDFilmTypes,\n url: movieUrl(movieId, { language: options?.language }),\n origins: getMovieOrigins(el),\n colorRating: getMovieColorRating(pageClasses),\n rating: getMovieRating(asideEl),\n ratingCount: getMovieRatingCount(asideEl),\n titlesOther: getMovieTitlesOther(el),\n poster: getMoviePoster(el),\n photo: getMovieRandomPhoto(el),\n trivia: getMovieTrivia(el),\n creators: getMovieCreators(el, options),\n vod: getMovieVods(asideEl),\n tags: getMovieTags(asideEl),\n premieres: getMoviePremieres(asideEl),\n related: getMovieBoxMovies(asideEl, 'Související'),\n similar: getMovieBoxMovies(asideEl, 'Podobné')\n };\n }\n}\n"],"mappings":";;;;;;AA4BA,IAAa,eAAb,MAA0B;CACxB,MAAa,MAAM,SAAiB,SAA2C;EAC7E,MAAM,KAAK,OAAO,QAAQ;AAC1B,MAAI,MAAM,GAAG,CACX,OAAM,IAAI,MAAM,gDAAgD;EAKlE,MAAM,YAAY,MAFD,MAAM,UADX,SAAS,IAAI,EAAE,UAAU,SAAS,UAAU,CAAC,EACnB,EAAE,GAAG,SAAS,SAAS,CAAC,CAE7B;EAEjC,MAAM,cAAc,UAAU,cAAc,gBAAgB,CAAC,WAAW,MAAM,IAAI;EAClF,MAAM,YAAY,UAAU,cAAc,uBAAuB;EACjE,MAAM,YAAY,UAAU,cAAc,sBAAsB;EAChE,MAAM,eAAe,UAAU,cAAc,uCAAqC,CAAC;EACnF,IAAI,SAA6B;AACjC,MAAI;AACF,YAAS,KAAK,MAAM,aAAa;WAC1B,GAAG;AACV,WAAQ,MAAM,wCAAwC,EAAE;;AAE1D,SAAO,KAAK,WAAW,CAAC,SAAS,WAAW,WAAW,aAAa,QAAQ,QAAQ;;CAGtF,AAAQ,WACN,SACA,IACA,SACA,aACA,QACA,SACW;AACX,SAAO;GACL,IAAI;GACJ,OAAO,cAAc,GAAG;GACxB,MAAM,aAAa,OAAO;GAC1B,UAAU,iBAAiB,QAAQ,GAAG;GACtC,cAAc,qBAAqB,GAAG;GACtC,QAAQ,eAAe,GAAG;GAC1B,MAAM,aAAa,GAAG;GACtB,KAAK,SAAS,SAAS,EAAE,UAAU,SAAS,UAAU,CAAC;GACvD,SAAS,gBAAgB,GAAG;GAC5B,aAAa,oBAAoB,YAAY;GAC7C,QAAQ,eAAe,QAAQ;GAC/B,aAAa,oBAAoB,QAAQ;GACzC,aAAa,oBAAoB,GAAG;GACpC,QAAQ,eAAe,GAAG;GAC1B,OAAO,oBAAoB,GAAG;GAC9B,QAAQ,eAAe,GAAG;GAC1B,UAAU,iBAAiB,IAAI,QAAQ;GACvC,KAAK,aAAa,QAAQ;GAC1B,MAAM,aAAa,QAAQ;GAC3B,WAAW,kBAAkB,QAAQ;GACrC,SAAS,kBAAkB,SAAS,cAAc;GAClD,SAAS,kBAAkB,SAAS,UAAU;GAC/C"}
1
+ {"version":3,"file":"movie.service.mjs","names":[],"sources":["../../src/services/movie.service.ts"],"sourcesContent":["import { HTMLElement, parse } from 'node-html-parser';\nimport { CSFDFilmTypes } from '../dto/global';\nimport { CSFDMovie, MovieJsonLd } from '../dto/movie';\nimport { fetchPage } from '../fetchers';\nimport {\n detectSeasonOrEpisodeListType,\n getEpisodeCode,\n getMovieBoxMovies,\n getMovieColorRating,\n getMovieCreators,\n getMovieDescriptions,\n getMovieDuration,\n getMovieGenres,\n getMovieOrigins,\n getMoviePoster,\n getMoviePremieres,\n getMovieRandomPhoto,\n getMovieRating,\n getMovieRatingCount,\n getMovieTags,\n getMovieTitle,\n getMovieTitlesOther,\n getMovieTrivia,\n getMovieType,\n getMovieVods,\n getMovieYear,\n getSeasonOrEpisodeParent,\n getSeasonsOrEpisodes,\n getSeriesAndSeasonTitle\n} from '../helpers/movie.helper';\nimport { CSFDOptions } from '../types';\nimport { movieUrl } from '../vars';\n\nexport class MovieScraper {\n public async movie(movieId: number, options?: CSFDOptions): Promise<CSFDMovie> {\n const id = Number(movieId);\n if (isNaN(id)) {\n throw new Error('node-csfd-api: movieId must be a valid number');\n }\n const url = movieUrl(id, { language: options?.language });\n const response = await fetchPage(url, { ...options?.request });\n\n const movieHtml = parse(response);\n\n const pageClasses = movieHtml.querySelector('.page-content').classNames.split(' ');\n const asideNode = movieHtml.querySelector('.aside-movie-profile');\n const movieNode = movieHtml.querySelector('.main-movie-profile');\n const jsonLdString = movieHtml.querySelector('script[type=\"application/ld+json\"]').innerText;\n let jsonLd: MovieJsonLd | null = null;\n try {\n jsonLd = JSON.parse(jsonLdString);\n } catch (e) {\n console.error('node-csfd-api: Error parsing JSON-LD', e);\n }\n return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);\n }\n\n private buildMovie(\n movieId: number,\n el: HTMLElement,\n asideEl: HTMLElement,\n pageClasses: string[],\n jsonLd: MovieJsonLd | null,\n options: CSFDOptions\n ) {\n const type = getMovieType(el) as CSFDFilmTypes;\n const { seriesName = null, seasonName = null } =\n type === 'season' ? getSeriesAndSeasonTitle(el) : {};\n const seasonOrEpisodeListType = detectSeasonOrEpisodeListType(el);\n\n const title = type === 'season' && seriesName ? seriesName : getMovieTitle(el);\n return {\n id: movieId,\n title,\n year: getMovieYear(jsonLd),\n duration: getMovieDuration(jsonLd, el),\n descriptions: getMovieDescriptions(el),\n genres: getMovieGenres(el),\n type,\n url: movieUrl(movieId, { language: options?.language }),\n origins: getMovieOrigins(el),\n colorRating: getMovieColorRating(pageClasses),\n rating: getMovieRating(asideEl),\n ratingCount: getMovieRatingCount(asideEl),\n titlesOther: getMovieTitlesOther(el),\n poster: getMoviePoster(el),\n photo: getMovieRandomPhoto(el),\n trivia: getMovieTrivia(el),\n creators: getMovieCreators(el, options),\n vod: getMovieVods(asideEl),\n tags: getMovieTags(asideEl),\n premieres: getMoviePremieres(asideEl),\n related: getMovieBoxMovies(asideEl, 'Související'),\n similar: getMovieBoxMovies(asideEl, 'Podobné'),\n seasons: seasonOrEpisodeListType === 'seasons' ? getSeasonsOrEpisodes(el) : null,\n episodes: seasonOrEpisodeListType === 'episodes' ? getSeasonsOrEpisodes(el) : null,\n parent: type === 'series' ? null : getSeasonOrEpisodeParent(el, { id: movieId, title }),\n episodeCode: type === 'episode' ? getEpisodeCode(el) : null,\n seasonName\n };\n }\n}\n"],"mappings":";;;;;;AAiCA,IAAa,eAAb,MAA0B;CACxB,MAAa,MAAM,SAAiB,SAA2C;EAC7E,MAAM,KAAK,OAAO,QAAQ;AAC1B,MAAI,MAAM,GAAG,CACX,OAAM,IAAI,MAAM,gDAAgD;EAKlE,MAAM,YAAY,MAFD,MAAM,UADX,SAAS,IAAI,EAAE,UAAU,SAAS,UAAU,CAAC,EACnB,EAAE,GAAG,SAAS,SAAS,CAAC,CAE7B;EAEjC,MAAM,cAAc,UAAU,cAAc,gBAAgB,CAAC,WAAW,MAAM,IAAI;EAClF,MAAM,YAAY,UAAU,cAAc,uBAAuB;EACjE,MAAM,YAAY,UAAU,cAAc,sBAAsB;EAChE,MAAM,eAAe,UAAU,cAAc,uCAAqC,CAAC;EACnF,IAAI,SAA6B;AACjC,MAAI;AACF,YAAS,KAAK,MAAM,aAAa;WAC1B,GAAG;AACV,WAAQ,MAAM,wCAAwC,EAAE;;AAE1D,SAAO,KAAK,WAAW,CAAC,SAAS,WAAW,WAAW,aAAa,QAAQ,QAAQ;;CAGtF,AAAQ,WACN,SACA,IACA,SACA,aACA,QACA,SACA;EACA,MAAM,OAAO,aAAa,GAAG;EAC7B,MAAM,EAAE,aAAa,MAAM,aAAa,SACtC,SAAS,WAAW,wBAAwB,GAAG,GAAG,EAAE;EACtD,MAAM,0BAA0B,8BAA8B,GAAG;EAEjE,MAAM,QAAQ,SAAS,YAAY,aAAa,aAAa,cAAc,GAAG;AAC9E,SAAO;GACL,IAAI;GACJ;GACA,MAAM,aAAa,OAAO;GAC1B,UAAU,iBAAiB,QAAQ,GAAG;GACtC,cAAc,qBAAqB,GAAG;GACtC,QAAQ,eAAe,GAAG;GAC1B;GACA,KAAK,SAAS,SAAS,EAAE,UAAU,SAAS,UAAU,CAAC;GACvD,SAAS,gBAAgB,GAAG;GAC5B,aAAa,oBAAoB,YAAY;GAC7C,QAAQ,eAAe,QAAQ;GAC/B,aAAa,oBAAoB,QAAQ;GACzC,aAAa,oBAAoB,GAAG;GACpC,QAAQ,eAAe,GAAG;GAC1B,OAAO,oBAAoB,GAAG;GAC9B,QAAQ,eAAe,GAAG;GAC1B,UAAU,iBAAiB,IAAI,QAAQ;GACvC,KAAK,aAAa,QAAQ;GAC1B,MAAM,aAAa,QAAQ;GAC3B,WAAW,kBAAkB,QAAQ;GACrC,SAAS,kBAAkB,SAAS,cAAc;GAClD,SAAS,kBAAkB,SAAS,UAAU;GAC9C,SAAS,4BAA4B,YAAY,qBAAqB,GAAG,GAAG;GAC5E,UAAU,4BAA4B,aAAa,qBAAqB,GAAG,GAAG;GAC9E,QAAQ,SAAS,WAAW,OAAO,yBAAyB,IAAI;IAAE,IAAI;IAAS;IAAO,CAAC;GACvF,aAAa,SAAS,YAAY,eAAe,GAAG,GAAG;GACvD;GACD"}