Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/dto/movie.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { CSFDScreening } from './global';

export interface MovieJsonLd {
dateCreated?: string | number;
duration?: string;
[key: string]: any;
}

export interface CSFDMovie extends CSFDScreening {
rating: number | null;
poster: string;
Expand Down
23 changes: 15 additions & 8 deletions src/helpers/movie.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
CSFDPremiere,
CSFDTitlesOther,
CSFDVod,
CSFDVodService
CSFDVodService,
MovieJsonLd
} from '../dto/movie';
import { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper';

Expand Down Expand Up @@ -123,22 +124,28 @@ export const getMovieRatingCount = (el: HTMLElement): number => {
}
};

export const getMovieYear = (el: string): number => {
export const getMovieYear = (jsonLd: string | MovieJsonLd | null): number => {
if (jsonLd === null) {
return null;
}
try {
const jsonLd = JSON.parse(el);
return +jsonLd.dateCreated;
const ld = typeof jsonLd === 'string' ? JSON.parse(jsonLd) : jsonLd;
return +ld.dateCreated;
} catch (error) {
console.error('node-csfd-api: Error parsing JSON-LD', error);
return null;
}
};
Comment on lines +127 to 138
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

+ld.dateCreated silently returns NaN when dateCreated is absent.

MovieJsonLd.dateCreated is optional β€” if the scraped JSON-LD doesn't include that field, ld.dateCreated is undefined, and +undefined evaluates to NaN. NaN is then propagated into CSFDMovie.year. Unlike null, NaN !== null is true, so consumers checking if (year !== null) will see a truthy but invalid value.

πŸ› Proposed fix β€” guard `dateCreated` before the unary `+`
  try {
    const ld = typeof jsonLd === 'string' ? JSON.parse(jsonLd) : jsonLd;
-   return +ld.dateCreated;
+   if (ld.dateCreated == null) return null;
+   const year = +ld.dateCreated;
+   return isNaN(year) ? null : year;
  } catch (error) {
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getMovieYear = (jsonLd: string | MovieJsonLd | null): number => {
if (jsonLd === null) {
return null;
}
try {
const jsonLd = JSON.parse(el);
return +jsonLd.dateCreated;
const ld = typeof jsonLd === 'string' ? JSON.parse(jsonLd) : jsonLd;
return +ld.dateCreated;
} catch (error) {
console.error('node-csfd-api: Error parsing JSON-LD', error);
return null;
}
};
export const getMovieYear = (jsonLd: string | MovieJsonLd | null): number => {
if (jsonLd === null) {
return null;
}
try {
const ld = typeof jsonLd === 'string' ? JSON.parse(jsonLd) : jsonLd;
if (ld.dateCreated == null) return null;
const year = +ld.dateCreated;
return isNaN(year) ? null : year;
} catch (error) {
console.error('node-csfd-api: Error parsing JSON-LD', error);
return null;
}
};
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helpers/movie.helper.ts` around lines 127 - 138, The getMovieYear
function can return NaN when ld.dateCreated is missing; update getMovieYear to
guard against absent/invalid dateCreated by: verify ld.dateCreated exists
(and/or coerce with Number or parseInt), check !Number.isNaN(value) and
Number.isFinite(value) before returning the numeric year, and return null if
dateCreated is undefined or not a valid number; also update the function
signature to reflect number | null if needed so CSFDMovie.year consumers don't
receive NaN. Use the getMovieYear and MovieJsonLd symbols to locate and change
the logic.


export const getMovieDuration = (jsonLdRaw: string, el: HTMLElement): number => {
export const getMovieDuration = (jsonLd: string | MovieJsonLd | null, el: HTMLElement): number => {
let duration = null;
try {
const jsonLd = JSON.parse(jsonLdRaw);
duration = jsonLd.duration;
return parseISO8601Duration(duration);
const ld = typeof jsonLd === 'string' ? JSON.parse(jsonLd) : jsonLd;
if (ld && ld.duration) {
duration = ld.duration;
return parseISO8601Duration(duration);
}
throw new Error('Duration not found in JSON-LD');
} catch (error) {
const origin = el.querySelector('.origin').innerText;
const timeString = origin.split(',');
Expand Down
17 changes: 14 additions & 3 deletions src/services/movie.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HTMLElement, parse } from 'node-html-parser';
import { CSFDFilmTypes } from '../dto/global';
import { CSFDMovie } from '../dto/movie';
import { CSFDMovie, MovieJsonLd } from '../dto/movie';
import { fetchPage } from '../fetchers';
import {
getLocalizedCreatorLabel,
Expand Down Expand Up @@ -41,7 +41,18 @@ export class MovieScraper {
const pageClasses = movieHtml.querySelector('.page-content').classNames.split(' ');
const asideNode = movieHtml.querySelector('.aside-movie-profile');
const movieNode = movieHtml.querySelector('.main-movie-profile');
const jsonLd = movieHtml.querySelector('script[type="application/ld+json"]').innerText;

const jsonLdNode = movieHtml.querySelector('script[type="application/ld+json"]');
const jsonLdString = jsonLdNode?.innerText || '';
let jsonLd: MovieJsonLd | null = null;
if (jsonLdString) {
try {
jsonLd = JSON.parse(jsonLdString);
} catch (e) {
console.error('node-csfd-api: Error parsing JSON-LD', e);
}
}

return this.buildMovie(+movieId, movieNode, asideNode, pageClasses, jsonLd, options);
}

Expand All @@ -50,7 +61,7 @@ export class MovieScraper {
el: HTMLElement,
asideEl: HTMLElement,
pageClasses: string[],
jsonLd: string,
jsonLd: MovieJsonLd | null,
options: CSFDOptions
): CSFDMovie {
return {
Expand Down