diff --git a/src/dto/movie.ts b/src/dto/movie.ts index fe088686..a37c2f24 100644 --- a/src/dto/movie.ts +++ b/src/dto/movie.ts @@ -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; diff --git a/src/helpers/movie.helper.ts b/src/helpers/movie.helper.ts index 230b4004..a824f80e 100644 --- a/src/helpers/movie.helper.ts +++ b/src/helpers/movie.helper.ts @@ -11,7 +11,8 @@ import { CSFDPremiere, CSFDTitlesOther, CSFDVod, - CSFDVodService + CSFDVodService, + MovieJsonLd } from '../dto/movie'; import { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper'; @@ -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; } }; -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(','); diff --git a/src/services/movie.service.ts b/src/services/movie.service.ts index e30470ac..83985e00 100644 --- a/src/services/movie.service.ts +++ b/src/services/movie.service.ts @@ -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, @@ -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); } @@ -50,7 +61,7 @@ export class MovieScraper { el: HTMLElement, asideEl: HTMLElement, pageClasses: string[], - jsonLd: string, + jsonLd: MovieJsonLd | null, options: CSFDOptions ): CSFDMovie { return {