diff --git a/demo.ts b/demo.ts index 620feaa..733b4b4 100644 --- a/demo.ts +++ b/demo.ts @@ -4,13 +4,13 @@ import { csfd } from './src'; // csfd.setOptions({ optionsRequest: { credentials: 'include' } }); // Parse movie -csfd.movie(10135).then((movie) => console.log(movie)); +csfd.movie(621073).then((movie) => console.log(movie)); // csfd.search('matrix').then((search) => console.log(search)); // csfd.cinema(1, 'today').then((cinema) => console.log(cinema)); // Parse creator -csfd.creator(2120).then((creator) => console.log(creator)); +// csfd.creator(2120).then((creator) => console.log(creator)); /** * USER RATINGS diff --git a/src/dto/movie.ts b/src/dto/movie.ts index aa1fca7..d64a8ab 100644 --- a/src/dto/movie.ts +++ b/src/dto/movie.ts @@ -17,6 +17,16 @@ export interface CSFDMovie extends CSFDScreening { premieres: CSFDPremiere[]; related: CSFDMovieListItem[]; similar: CSFDMovieListItem[]; + seasons: CSFDSeason[] | null; + episodes: CSFDSeason[] | null; + parent: CSFDParent | null; + episodeCode: string | null; + seasonName: string | null; +} + +export interface CSFDParent { + season: { id: number; name: string } | null; + series: { id: number; name: string } | null; } export interface MovieJsonLd { @@ -151,7 +161,6 @@ export type CSFDCreatorGroups = | 'Scénografie' | 'Kostýmy'; - export type CSFDCreatorGroupsEnglish = | 'Directed by' | 'Screenplay' @@ -187,3 +196,10 @@ export interface CSFDPremiere { } export type CSFDBoxContent = 'Související' | 'Podobné'; + +export interface CSFDSeason { + id: number; + name: string; + url: string; + info: string | null; +} diff --git a/src/helpers/global.helper.ts b/src/helpers/global.helper.ts index eef6d14..e1045a4 100644 --- a/src/helpers/global.helper.ts +++ b/src/helpers/global.helper.ts @@ -16,6 +16,16 @@ export const parseIdFromUrl = (url: string): number => { return +id || null; }; +export const parseLastIdFromUrl = (url: string): number => { + if (url) { + const idSlug = url?.split('/')[3]; + const id = idSlug?.split('-')[0]; + return +id || null; + } else { + return null; + } +}; + export const getColor = (cls: string): CSFDColorRating => { switch (cls) { case 'page-lightgrey': diff --git a/src/helpers/movie.helper.ts b/src/helpers/movie.helper.ts index 2f17191..0dbca71 100644 --- a/src/helpers/movie.helper.ts +++ b/src/helpers/movie.helper.ts @@ -9,14 +9,22 @@ import { CSFDGenres, CSFDMovieCreator, CSFDMovieListItem, + CSFDParent, CSFDPremiere, + CSFDSeason, CSFDTitlesOther, CSFDVod, CSFDVodService, MovieJsonLd } from '../dto/movie'; import { CSFDOptions } from '../types'; -import { addProtocol, getColor, parseISO8601Duration, parseIdFromUrl } from './global.helper'; +import { + addProtocol, + getColor, + parseISO8601Duration, + parseIdFromUrl, + parseLastIdFromUrl +} from './global.helper'; const CREATOR_LABELS: Record< string, @@ -101,6 +109,26 @@ export const getMovieId = (el: HTMLElement): number => { return parseIdFromUrl(url); }; +export const getSeriesAndSeasonTitle = ( + el: HTMLElement +): { seriesName: string | null; seasonName: string | null } => { + const titleElement = el.querySelector('h1'); + if (!titleElement) { + return { seriesName: null, seasonName: null }; + } + + const fullText = titleElement.innerText.trim(); + + // Check if there's a series part indicated by ' - ' + if (fullText.includes(' - ')) { + const [seriesName, seasonName] = fullText.split(' - ').map((part) => part.trim()); + return { seriesName, seasonName }; + } + + // If no series part found, return just the name + return { seriesName: fullText, seasonName: null }; +}; + export const getMovieTitle = (el: HTMLElement): string => { return el.querySelector('h1').innerText.split(`(`)[0].trim(); }; @@ -321,6 +349,91 @@ export const getMovieCreators = (el: HTMLElement, options?: CSFDOptions): CSFDCr return creators; }; +export const getSeasonsOrEpisodes = ( + el: HTMLElement, + serie?: { id: number; title: string } +): CSFDSeason[] | null => { + const childrenList = el.querySelector('.film-episodes-list'); + if (!childrenList) return null; + + const childrenNodes = childrenList.querySelectorAll('.film-title'); + if (!childrenNodes?.length) return []; + + return childrenNodes.map((season) => { + const nameContainer = season.querySelector('.film-title-name'); + const infoContainer = season.querySelector('.info'); + + return { + id: parseLastIdFromUrl(nameContainer?.getAttribute('href') || ''), + name: nameContainer?.textContent?.trim() || null, + url: nameContainer?.getAttribute('href') || null, + info: infoContainer?.textContent?.replace(/[{()}]/g, '').trim() || null + }; + }); +}; + +export const getEpisodeCode = (el: HTMLElement): string | null => { + const filmHeaderName = el.querySelector('.film-header-name h1'); + if (!filmHeaderName) return null; + + const text = filmHeaderName.textContent?.trim() || ''; + const match = text.match(/\(([^)]+)\)/); + const code = match ? match[1] : null; + + return code; +}; + +export const detectSeasonOrEpisodeListType = (el: HTMLElement) => { + const headerText = el.querySelector('.box-header h3')?.innerText.trim() ?? ''; + + if (headerText.includes('Série')) return 'seasons'; + if (headerText.startsWith('Epizody')) return 'episodes'; + return null; +}; + +export const getSeasonOrEpisodeParent = ( + el: HTMLElement, + serie?: { id: number; name: string } +): CSFDParent | null => { + // Try h2 first (for episodes), then h1 (for seasons) + let parents = el.querySelectorAll('.film-header h2 a'); + if (parents.length === 0) { + parents = el.querySelectorAll('.film-header h1 a'); + } + + if (parents.length === 0) { + if (!serie) return null; + return { series: serie, season: null }; + } + + const [parentSeries, parentSeason] = parents; + + const seriesId = parseIdFromUrl(parentSeries?.getAttribute('href')); + const seasonId = parseLastIdFromUrl(parentSeason?.getAttribute('href') || ''); + const seriesName = parentSeries?.textContent?.trim() || null; + const seasonName = parentSeason?.textContent?.trim() || null; + + const series = seriesId && seriesName ? { id: seriesId, name: seriesName } : null; + const season = seasonId && seasonName ? { id: seasonId, name: seasonName } : null; + + if (!series && !season) return null; + + return { series, season }; +}; + +export const getMovieGroup = ( + el: HTMLElement, + group: CSFDCreatorGroups | CSFDCreatorGroupsEnglish | CSFDCreatorGroupsSlovak +): CSFDMovieCreator[] => { + const creators = el.querySelectorAll('.creators h4'); + const element = creators.filter((elem) => elem.textContent.trim().includes(group))[0]; + if (element?.parentNode) { + return parseMoviePeople(element.parentNode as HTMLElement); + } else { + return []; + } +}; + export const getMovieType = (el: HTMLElement): string => { const type = el.querySelector('.film-header-name .type'); return type?.innerText?.replace(/[{()}]/g, '') || 'film'; diff --git a/src/services/movie.service.ts b/src/services/movie.service.ts index f61c146..92bf005 100644 --- a/src/services/movie.service.ts +++ b/src/services/movie.service.ts @@ -3,6 +3,8 @@ import { CSFDFilmTypes } from '../dto/global'; import { CSFDMovie, MovieJsonLd } from '../dto/movie'; import { fetchPage } from '../fetchers'; import { + detectSeasonOrEpisodeListType, + getEpisodeCode, getMovieBoxMovies, getMovieColorRating, getMovieCreators, @@ -21,7 +23,10 @@ import { getMovieTrivia, getMovieType, getMovieVods, - getMovieYear + getMovieYear, + getSeasonOrEpisodeParent, + getSeasonsOrEpisodes, + getSeriesAndSeasonTitle } from '../helpers/movie.helper'; import { CSFDOptions } from '../types'; import { movieUrl } from '../vars'; @@ -57,15 +62,21 @@ export class MovieScraper { pageClasses: string[], jsonLd: MovieJsonLd | null, options: CSFDOptions - ): CSFDMovie { + ) { + const type = getMovieType(el) as CSFDFilmTypes; + const { seriesName = null, seasonName = null } = + type === 'série' ? getSeriesAndSeasonTitle(el) : {}; + const seasonOrEpisodeListType = detectSeasonOrEpisodeListType(el); + + const title = type === 'série' && seriesName ? seriesName : getMovieTitle(el); return { id: movieId, - title: getMovieTitle(el), + title, year: getMovieYear(jsonLd), duration: getMovieDuration(jsonLd, el), descriptions: getMovieDescriptions(el), genres: getMovieGenres(el), - type: getMovieType(el) as CSFDFilmTypes, + type, url: movieUrl(movieId, { language: options?.language }), origins: getMovieOrigins(el), colorRating: getMovieColorRating(pageClasses), @@ -80,7 +91,12 @@ export class MovieScraper { tags: getMovieTags(asideEl), premieres: getMoviePremieres(asideEl), related: getMovieBoxMovies(asideEl, 'Související'), - similar: getMovieBoxMovies(asideEl, 'Podobné') + similar: getMovieBoxMovies(asideEl, 'Podobné'), + seasons: seasonOrEpisodeListType === 'seasons' ? getSeasonsOrEpisodes(el) : null, + episodes: seasonOrEpisodeListType === 'episodes' ? getSeasonsOrEpisodes(el) : null, + parent: type === 'seriál' ? null : getSeasonOrEpisodeParent(el, { id: movieId, name: title }), + episodeCode: type === 'epizoda' ? getEpisodeCode(el) : null, + seasonName }; } } diff --git a/tests/fetchers.test.ts b/tests/fetchers.test.ts index 714ce01..2f2f43b 100644 --- a/tests/fetchers.test.ts +++ b/tests/fetchers.test.ts @@ -159,25 +159,102 @@ describe('Live: Movie page. Fetch `10135-forrest-gump`', () => { }); }); -describe('Live: Tv series', () => { - let movie: CSFDMovie = {} as CSFDMovie; - beforeAll(async () => { - movie = await csfd.movie(71924); - }); - test('Year', () => { - expect(movie.year).toEqual(1994); +describe('Live: Series Patterns', () => { + // Pattern 1: Series with Seasons (The Simpsons) + describe('Series with Seasons (The Simpsons)', () => { + let movie: CSFDMovie; + beforeAll(async () => { + movie = await csfd.movie(72489); + }); + test('Type and Title', () => { + expect(movie.type).toEqual('seriál'); + expect(movie.title).toEqual('Simpsonovi'); + }); + test('Seasons', () => { + expect(movie.seasons).toBeDefined(); + expect(movie.seasons!.length).toBeGreaterThan(20); + }); + test('No Episodes on main page', () => { + expect(movie.episodes).toBeNull(); + }); }); - test('Type', () => { - expect(movie.type).toEqual('seriál'); + + // Pattern 1: Season Page (The Simpsons S01) + describe('Season Page (The Simpsons S01)', () => { + let movie: CSFDMovie; + beforeAll(async () => { + movie = await csfd.movie(474212); + }); + test('Type and Title', () => { + expect(movie.type).toEqual('série'); + expect(movie.title).toEqual('Simpsonovi'); + expect(movie.seasonName).toEqual('Série 1'); + }); + test('Parent Series', () => { + expect(movie.parent?.series?.id).toEqual(72489); + expect(movie.parent?.season).toBeNull(); + }); + test('Episodes', () => { + expect(movie.episodes).toBeDefined(); + expect(movie.episodes!.length).toBeGreaterThan(0); + }); }); - test('Title', () => { - expect(movie.title).toEqual('Království'); + + // Pattern 1: Episode Page (The Simpsons S01E08) + describe('Episode Page (The Simpsons S01E08)', () => { + let movie: CSFDMovie; + beforeAll(async () => { + movie = await csfd.movie(474220); + }); + test('Type and Title', () => { + expect(movie.type).toEqual('epizoda'); + expect(movie.title).toEqual('Mluvící hlava'); + }); + test('Episode Code', () => { + expect(movie.episodeCode).toEqual('S01E08'); + }); + test('Parents', () => { + expect(movie.parent?.series?.id).toEqual(72489); + expect(movie.parent?.season?.id).toEqual(474212); + }); }); - test('Duration', () => { - expect(movie.duration).toBeGreaterThan(50); + + // Pattern 2: Series without Seasons (The Curse) + describe('Series without Seasons (The Curse)', () => { + let movie: CSFDMovie; + beforeAll(async () => { + movie = await csfd.movie(1431651); + }); + test('Type and Title', () => { + expect(movie.type).toEqual('seriál'); + expect(movie.title).toEqual('The Curse'); + }); + test('Episodes directly', () => { + expect(movie.episodes).toBeDefined(); + expect(movie.episodes!.length).toBeGreaterThan(0); + }); + test('No Seasons', () => { + expect(movie.seasons).toBeNull(); + }); }); - test('Fetch not number', async () => { - await expect(csfd.movie('test' as any)).rejects.toThrow(Error); + + // Pattern 2: Episode without Season (The Curse E01) + describe('Episode without Season (The Curse E01)', () => { + let movie: CSFDMovie; + beforeAll(async () => { + movie = await csfd.movie(1436408); + }); + test('Type and Title', () => { + expect(movie.type).toEqual('epizoda'); + expect(movie.title).toEqual('Kouzelná země'); + }); + test('Episode Code', () => { + expect(movie.episodeCode).toEqual('E01'); + }); + test('Parents', () => { + expect(movie.parent?.series?.id).toEqual(1431651); + expect(movie.parent?.season).toBeNull(); + }); }); }); diff --git a/tests/mocks/series1-season1-episode.mock.ts b/tests/mocks/series1-season1-episode.mock.ts new file mode 100644 index 0000000..8f936ec --- /dev/null +++ b/tests/mocks/series1-season1-episode.mock.ts @@ -0,0 +1,1363 @@ +export const serie1Season1EpisodeMock = ` + + + + + + + + Simpsonovi - Mluvící hlava (S01E08) (1990) | ČSFD.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Reklama

+
+
+
+ +
+
+
+

+ Change website language +

+

+ + Do not switch + +

+
+
+ + + + +
+ + + +
+ +
+
+
+ +
+
+
+ +
+

+ Simpsonovi + - Série 1 (1989) (série) +

+
+
+

+ + Mluvící hlava + (S01E08) +

+ (epizoda) + + + + + + + + + +
    +
  • +USA The Telltale Head + + (více) + +
  • + + + + +
+
+
+
+ + +
+
+ + + + + + více + + +
+ + + + + +
+
+
+
+
+
+
+
+ 86% + +
+ +
+ + + + Hodnocení a fanklub + + +
+ + +
USA, + 1990, 22 min + + +
+ + +
+
+
+
+ +
+
+

VOD (3)

+ +
+ +
+ + + + +
+
+

+ Obsahy(1) + + +

+
+
+
+
+ + +

+ Bart ve snaze šplhnout si před partou ukradne hlavu sochy zakladatele města Springfieldu. Zděšení a pobouření zavládne mezi občany i povedenými kumpány Barta. Nakonec se Bart s Homerem snaží hlavu vrátit, přičemž jen o vlas uniknou lynčování... + + + (Česká televize) + +

+
+ +
+
+
+ + + +
+ + + +
+
+ +
+
+ +
+
+

Recenze (16)

+
+ VÍCE +
+
+
+
+
+
+
+

Loki_Six 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + "Uh, ma'am, what if you're a really good person but you're in a really, really, really bad fight and your leg gets gangrene and has to be amputated. Will it be waiting for you in heaven?" + + + + + + () + +

+ + +
+
+ + + +
+
+
+ + +
+
+
+
+

Wyrdas 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Cesta do kostela byla super, omáčka okolo také... ale hlavní příběh byl takový plytký. Typicky nucený pokus o moralizaci, který mi do takového seriálu moc nepasuje. Nebylo to zlé, ale když si vzpomenu na uříznutou hlavu J.S., vybaví se mi jako první Southpark. A toto zastíní v mém hodnocení poslední hvězdu. Poučení z epizody: Barbarství jednotlivce či skupiny vymýtíme ubitím davem na ulici. - A přitom by stačilo useknout ruku. + + + + + + () + +

+ + +
+
+ +
+
+
+
+
+
+
+

Cheeter 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + První série Simpsonů u mě nadšení nikdy nějak nadšení nebudila a stejně je na tom i tahle epizoda. Velmi jednoduchý děj s téměř nulovými vtipy. + + + + + + () + +

+ + +
+
+ +
+
+ +
+
+

Galerie (8)

+
+ VÍCE +
+
+
+
+ +
+
+

Zajímavosti (14)

+
+ VÍCE +
+
+
+
+
+
    +
  • +Jde o jednu z mála epizod, jejíž název se objeví v úvodních titulcích. + + + (henrycruel) + + + +
  • +
+
+
+
+
+
    +
  • +Scéna, ve které se Bart probudí s hlavou sochy v posteli, je parodií na film Kmotr (1972). Bartova hláška v původním znění "Top of the world, ma" je zase narážka na Bílý žár (1949). + + + (henrycruel) + + + +
  • +
+
+
+
+
+
    +
  • +Mezi rozzuřeným davem, který pronásleduje Barta a Homera, jsou i děda Simpson a Patty se svou sestrou Selmou. + + + (henrycruel) + + + +
  • +
+
+
+
+
+ + +
+ + + +
+
+ + +
+ +
+
+

Reklama

+
+
+
+
+
+

Reklama

+
+
+
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + + + + + + + +`; diff --git a/tests/mocks/series1-season1.mock.ts b/tests/mocks/series1-season1.mock.ts new file mode 100644 index 0000000..77e4c59 --- /dev/null +++ b/tests/mocks/series1-season1.mock.ts @@ -0,0 +1,1425 @@ +export const serie1Season1Mock = ` + + + + + + + + Simpsonovi - Série 1 (S01) (1989) | ČSFD.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Reklama

+
+
+
+ +
+
+
+

+ Change website language +

+

+ + Do not switch + +

+
+
+ + + + +
+ + + +
+ +
+
+
+ +
+ +
+ +
+
+

VOD (3)

+ +
+ +
+ + + +
+
+

+ Epizody(13) +

+
+
+
+ +
+
+
+ +
+
+

+ Obsahy(1) + + +

+
+
+
+ +
+ + +

+ Nejsledovanější americká rodina na svém počátku. V městečku Springfield žije rodina Simpsonových - uličník Bart, chytrá Líza, líný Homer, malá Maggie a starostlivá Marge. Tato rodina prožívá život plný zážitků. V první sérii se dozvíte, jak probíhají Vánoce u Simpsonových, jak se má Bart ve Francii, jestli je Bart opravdu malý génius nebo třeba jak se pomstít Nelsonovi, a zdali je Šáša opravdu vinen. + + + (Varan) + +

+ (více) +
+ +
+
+
+ + + +
+ + + +
+
+ +
+
+ +
+
+

Recenze (25)

+
+ VÍCE +
+
+
+
+
+
+
+

Pierre 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Ještě poměrně pomalý úvod. Klasický humor Simpsnů ještě neobsahuje. Je zde (možná překvapivě) i pár melancholických dílů, u kterých se moc nenasmějete. Mám rád díl Ve víru vášně, ten je třeba moc milý a dojemný. A ještě Vánoce jsou solidní. Zbytek je spíš nuda. Hezkej večer je třeba dost primitivní epizoda. Hvězdné časy teprve měli přijít. + + + + + + () + +

+ + +
+
+ +
+
+
+
+

KuceraJohny 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Po mnoho letech jsem si zopakoval celou první sérii a musím říct, že rozhodně nebude tou mou nejoblíbenější. První díl mám velmi rád a pak asi další tři, ale většina je zkrátka průměr, který neurazí ani nenadchne. Nechci být divákem, který bude hodnotit jen na základě toho, že tohle jsou přece ty začátky, ty originální Simpsonovi. Pro mě ne, já mám nejraději ty o pár let novější. První série ještě není zajetá a spíše zkouší. Jednotlivá místa, občas nevypadají tak jak si je pamatuji, postavy se v podstatě ještě neznají a o co hůř i když se o pár epizod před tím poznají, tak najednou se zase neznají. Je to takové nejisté, ale né nejhorší. Vždycky jsem se celkem bavil, ale míň než jsem u Simpsonových zvyklý. + + + + + + () + +

+ + +
+
+

Reklama

+
+
+
+ +
+
+
+
+
+
+
+

MM_Ramone 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + 01. Vánoce u Simpsonových, 02. Malý génius, 03. Homerova odysea, 04. Taková nenormální rodinka, 05. Bart generálem aneb Kdopak by se Nelsona bál, 06. Smutná Líza, 07. Volání přírody, 08. Mluvící hlava, 09. Ve víru vášně, 10. Světák Homer, 11. Kyselé hrozny sladké Francie, 12. Je Šáša vinen?, 13. Hezkej večer ***** + + + + + + () + +

+ + +
+
+ +
+
+
+
+

Wyrdas 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Nu, průměr všech hodnocení z první sezóny nám dává silné čtyři hvězdy. Každý díl jsem okomentoval ohledně poučení, které z něj vychází a seriózně přemýšlel nad tím, proč už jsem to někde viděl. Občas jsem si musel připomenout, že to až další série přehrávají ty samé skeče a zde je vše ještě liliově čisté. Mnoho hlášek z první série se stalo legendárními a nikdy je nezapomenu. Už jen za to všechna čest a sláva, která jak již víme, pomalinku ale jistě bude jen blednout. Zatím super. + + + + + + () + +

+ + +
+
+ +
+
+
+
+
+
+
+

Lachtaan 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Samotný začátek nesmrtelného nežlutého fenoménu je ohromnou nostalgií a i když mnozí ovlivnění dnešní animací tu počáteční nemusejí, já protáhlé jednoduché obličeje naší praštěné rodinky prostě žeru. +Nejlepší díly - Bárt generálem aneb Kdopak by se Nelsona bál, Smutná Líza a Kyselé hrozny Sladké Francie. +Celkově - 10/10! + + + + + + () + +

+ + +
+
+ +
+
+ +
+
+

Galerie (69)

+
+ VÍCE +
+
+
+
+ +
+
+

Zajímavosti (262)

+
+ VÍCE +
+
+
+
+
+
    +
  • +Když je Homer před svým domem, tak prohlásí, že pošlapal pár zvadlých kytek. V následujících záběrech se kytky střídavě objevují a mizí. + + + (Duoscop) + + + +
  • +
+
+
+
+
+
    +
  • +Pôvodne mala byť vysielaná iná epizóda (Some Enchanted Evening), ale kvôli animácii, ktorá dopadla katastrofálne, ju museli prerobiť. + + + (JakubZhrnuje) + + + +
  • +
+
+
+
+
+
    +
  • +V této epizodě se poprvé objevili: šerif Clancy Wiggum, Waylon Smithers, řidič autobusu Otto Mann, důchodce Jasper Beardly nebo Bartův spolužák Wendell Borton. + + + (henrycruel) + + + +
  • +
+
+
+
+
+ + +
+ + + +
+
+ + +
+ +
+
+

Reklama

+
+
+
+
+
+

Reklama

+
+
+
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + + + + + + + + +`; diff --git a/tests/mocks/series1-seasons.mock.ts b/tests/mocks/series1-seasons.mock.ts new file mode 100644 index 0000000..b62f592 --- /dev/null +++ b/tests/mocks/series1-seasons.mock.ts @@ -0,0 +1,2620 @@ +export const serie1SeasonsMock = ` + + + + + + + + Simpsonovi (1989) | ČSFD.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Reklama

+
+
+
+ +
+
+
+

+ Change website language +

+

+ + Do not switch + +

+
+
+ + + + +
+ + + +
+ +
+
+
+ +
+
+
+ +
+
+

+ + Simpsonovi + +

+ (seriál) + + + + + + + + +
    +
  • +USA The Simpsons + + (více) + +
  • + +
+
+
+
+
+ + všechny plakáty + +
+ +
+
+
+
+
+ + + + Trailer + + + + +
+ +
+
+
+
+
+
+ +
+
+ + + +
USA, + (1989–2026), 296 h 16 min + (Minutáž: 20–45 min) + +
+ +
+ + +
+

Scénář:

+John Swartzwelder, Dan Greaney, David X. Cohen, Richard Appel (více) +
+ +
+

Hrají:

+Dan Castellaneta, Julie Kavner, Nancy Cartwright, Yeardley Smith, Harry Shearer, Hank Azaria, Marcia Wallace, Pamela Hayden, Tress MacNeille, Russi Taylor (více) +
+ + + + + (další profese) +
+
+
+
+
+ +
+ + +
+ + + +
+
+

+ Série(38) / Epizody(819) +

+
+
+
+ +
+ +
+
+ +
+
+

+ Obsahy(1) + + +

+
+
+
+ +
+ + +

+ Natvrdlý lenoch Homer, pedantská puťka Marge, drzounský Bart, přechytralá Líza a roztomilá Maggie – to jsou členové rodiny nejslavnějšího a nejpopulárnějšího animovaného seriálu Simpsonovi. Už dvacet let se jich miliony fanoušků na celém světě nemohou nabažit a v pravidelných intervalech nakukují do zákulisí legendárního Springfieldu, aby byli svědky neuvěřitelných dobrodružství bláznivé, ale přesto vlastně normální americké rodinky. Simpsonovi si získali své obecenstvo především neotřelým a trochu drsným humorem, s nímž vykreslují typickou americkou rodinu z městečka Springfield. Ta se skládá z pěti naprosto odlišných lidí, pro které je občas pořádně těžké se sebou vyjít. Nemluvě o ostatních obyvatelích města, v němž to opravdu neustále žije – je tu vlastní upadlá kultura, zkorumpovaná politika, drsná mafie a lenivá policie, ale také prostí občané, kteří se každý týden chodí kát do místního kostela. V neposlední řadě si mohou diváci všimnout jednoho všudypřítomného detailu – Simpsonovi totiž téměř v každé scénce něco nebo někoho parodují – ať už jde o svět filmový, hudební, politický, ale i náboženský. Tvůrci seriálu se zkrátka s velkou odvahou pouštějí do neustálých provokací osob a institucí z reálného života. + + + (TV Prima) + +

+ (více) +
+ +
+
+
+ + + +
+ + + +
+
+
+

Videa (5)

+
+ VÍCE +
+
+
+
+
+
+
+ + + + Trailer + + + + +
+ +
+
+
+
+
+
+ +
+
+

Recenze (2 503)

+
+ VÍCE +
+
+
+
+
+
+
+

Malarkey 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + Rozhodně nejlepší animovaný seriál, který nemá ani na Futuramu jelikož je mi zde naprosto každá postava sympatická a to se jen tak některém seriálu nestane. Homer J. Simpson je naprosto dokonalý povaleč a mám ho fakt moc rád. Mimo to jeho dabing, který v naší kotlině vznikl je naprosto dokonalý. No on je celkově celý dabing simpsonů opravdu velice slušný a to se velice cenní. Ještě, že se autoři retušovali tím, že seriál jen tak nenechají skončit. jinak bychom přišli o rozhodně nejoblíbenější a nejvtipnější americkou rodinku současnosti. (98%) + + + + + + () + +

+ + +
+
+ +
+
+
+
+

gudaulin 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + Poprvé jsem se s fenoménem rodinky Simpsonových setkal ve videoklipu na MTV koncem roku 1990 a ještě jsem netušil, že mám tu čest seznámit se s největším projektem a kultem v oblasti animované tvorby. Tehdy mě vyvedlo z míry trochu ztřeštěné výtvarné pojetí postaviček i jejich zvláštní namluvení, ale ihned poté, co byl seriál uveden na naše obrazovky, jsem mu úplně propadl. Jeden ze dvou seriálů, který od mne má stoprocentní hodnocení za celkový dojem a u kterého necítím ani po letech nějaké zřejmé opotřebování. Hlasy, které argumentují, že seriál ztrácí šmrnc a upadá do průměru, spíš reflektují únavu jednotlivých diváků z projektu, který trvá tak dlouho. Ve skutečnosti byl seriál v řadě ohledů na počátku krotší a teprve jak běžel čas a bylo nutné udržet diváky u obrazovek, tvůrci přitvrdili. To, jak dlouho se seriál dokázal udržet v hlavním vysílacím čase, je na poměry amerického televizního trhu neuvěřitelné. Seriál byl zároveň úspěšný prakticky ve všech zemích, kde byl odvysílán, a v řadě případů je hlavním zdrojem informací o americké společnosti.:-) Celá řada amerických celebrit se ucházela o poctu být v seriálu aspoň zmíněna nebo si tam zahrát malou roličku. Početný tvůrčí tým skvěle pracuje s popkulturními odkazy a drží styl ironické nadsázky a parodování představ o životě americké společnosti. Svými sympatiemi k obyčejnému řadovému člověku a zpochybňováním obrazu bohabojného a ušlechtilého amerického občana se scénáristé podle všeho řadí k americké liberální levici. Je to poznat ze spousty narážek na republikány, patetické vlastenectví a v Americe vysoce citlivou oblast náboženské víry. Seriál si dokonce vysloužil kritiku od amerického prezidenta za poškozování obrazu země v zahraničí...Zároveň si tvůrci toho malého človíčka nijak neidealizují a podávají ho se všemi jeho slabůstkami a necnostmi. Spousta hlášek, vtípků a ujetých postaviček, díky kterým stojí za to i po letech sednout k televizní obrazovce a zaposlouchat se do tónů známé znělky. Škoda, že u nás, v zemi s takovou tradicí animované tvorby nevzniklo nic, co by se aspoň vzdáleně Simpsonovým podobalo... + + + + + + () + +

+ + +
+
+

Reklama

+
+
+
+ +
+
+
+
+
+
+
+

Renton 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Creator & developed: Matt Groening, James L. Brooks, Sam Simon .. WHAT THE F..amily!? Dokonalý animovaný NÁŘEZ!!! Většinou ultimátní zábava, někdy sice zakulhá, ale téměř vždy pobaví, pohladí po duši a každý si to zkrátka užije. Neuvěřitelně originální a vypointované příběhy plus výtečná postava otce/flákače/pivaře Homera - to je punc geniality. Reakce na současnou situaci a problémy společnosti už od roku 1989 a narážky na všechno a všechny. KDO NEZNÁ TENTO LEGENDÁRNÍ ANIMOVANÝ SERIÁL, NEŽIJE NA NAŠÍ PLANETĚ !!.. 100%. + + + + + + () + +

+ + +
+
+ +
+
+
+
+

Jara.Cimrman.jr 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Jako vážený springfieldský rodák, nemanželský potomek Neda Flenderse a jakési žluté potvory, mohu hrdě prohlásit, že jsem viděl všechna povyražení geniálního Homera Simpsona a jeho milované rodiny. A jelikož předcházející tvrzení patrně není pravda, tak dávám pět hvězd jako omluvu sám sobě za to, že jsem se pitomě okradl o nějakou tu minutu skvěle satirické zábavy. + + + + + + () + +

+ + +
+
+ +
+
+
+
+
+
+
+

lamps 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Dlouho jsem přemýšlel, jak svůj platonický vztah k Simpsonovým v jednoduchosti vyjádřit. Ano, série 20+ už mě moc nebaví, ale především prvních devět (což je pořád skoro dvě stě epizod) jsou pro mě asi nejformativnějším uměleckým dílem vůbec. Drobky z dané éry si pouštím takřka každý den a bez přehánění jim vděčím za mnohé – nejvíce asi za to, jak uhňácaly můj vlastní smysl pro humor. Každá devadesátková epizoda je narvaná gagy a situacemi, které můžete vztáhnout na vlastní každodennost takovou mírou, že si to mnohdy ani neuvědomujeme. A pokud nás to zrovna napadne, máme v kapse nějaký univerzální a skvělý vtípek. Simpsonovi mě naučili usmát se nad věcmi, které některým podlamují kolena, a navrch mě vedli emocionálním dozráváním více než jakýkoli jiný pořad či film – například epizoda A s Maggie jsou tři mě s jistotou pokaždé rozbrečí a úžasně šperkuje náturu bezkonkurenčního Homerova charakteru, který opravdu býval tou nejlepší a nejpropracovanější televizní postavou. Simpsonovi ze mě, aspoň si myslím, udělali lepšího, zábavnějšího a empatičtějšího člověka, a za to jim nikdy nepřestanu být vděčný... + + + + + + () + +

+ + +
+
+ +
+
+ +
+
+

Galerie (3 701)

+
+ VÍCE +
+
+
+
+ +
+
+

Zajímavosti (4 502)

+
+ VÍCE +
+
+
+
+
+
    +
  • +Šerif Clancy Wiggum je původem z Irska. + + + (Delock) + + + +
  • +
+
+
+
+
+
    +
  • +V epizodě Starý zbabělec se ukáže, že oním zbabělcem je pes Spasitel, když nezachrání Homera z hořícího dřevěného domku nahoře ve větvích stromu. V epizodě Spasitel zabijákem nicméně Spasitel zachrání malé dítě z hořícího dřevěného srubu. + + + (CANNIBAL) + + + +
  • +
+
+
+
+
+
    +
  • +V roce 2014 se stal Petr Čech spolu s dalšími čtyřmi hráči britského fotbalového klubu Chelsea předlohou pro simpsonovské suvenýry. + + + (Kmotr76) + + + +
  • +
+
+
+
+
+ + +
+ + + +
+
+

Související novinky

+
+ více +
+
+
+
+
+
+
+
+
+ + Simpsonovi opět míří do filmu + +
+
+

+ Simpsonovi opět míří do filmu +

+
+ 29.09.2025 +
+
+
+
+

+ Chyběla vám nejznámější animovaná televizní rodina? Budiž pro vás dobrou zprávou, že po dvaceti letech bude v kinech opět pořádně žluto! Legendární animovaní Simpsonovi z dílny Matta Groeninga se… + (více) +

+
+
+
+
+
+
+
+
+
+ + Disney+ odstartuje v Česku 14. června + +
+
+

+ Disney+ odstartuje v Česku 14. června +

+
+ 29.03.2022 +
+
+
+
+

+ A je to oficiální. Společnost The Walt Disney Company potvrdila, že streamovací služba Disney+ dorazí do Česka a na Slovensko 14. června, základní měsíční předplatné bude stát 199 Kč, roční pak vyjde… + (více) +

+
+
+
+
+
+
+
+
+
+ + Zemřela herečka Betty White + +
+
+

+ Zemřela herečka Betty White +

+
+ 01.01.2022 +
+
+
+
+

+ Zbožňovaná herečka a komediální ikona Betty White zemřela ve věku 99 let pár hodin před koncem roku 2021. Do stých narozenin jí přitom zbývalo už jen pár týdnů. Herečka byla poslední přeživší členkou… + (více) +

+
+
+
+
+
+
+
+
+
+ + Simpsonovi ztratí známý hlas + +
+
+

+ Simpsonovi ztratí známý hlas +

+
+ 21.01.2020 +
+
+
+
+

+ Postava Apua Nahasapeemapetilona z kultovního seriálu Simpsonovi prožila v posledních pár měsících svoji vlastní kontroverzi. Spousta lidí se totiž sekla na tom, že postava je de facto jen výčtem… + (více) +

+
+
+
+
+
+
+
+
+
+
+
+ + +
+ +
+
+

Reklama

+
+
+
+
+
+

Reklama

+
+
+
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + + + + + + + +`; diff --git a/tests/mocks/series2-episode.mock.ts b/tests/mocks/series2-episode.mock.ts new file mode 100644 index 0000000..3483a4c --- /dev/null +++ b/tests/mocks/series2-episode.mock.ts @@ -0,0 +1,1255 @@ +export const serie2EpisodeMock = ` + + + + + + + + The Curse - Kouzelná země (E01) (2023) | ČSFD.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Reklama

+
+
+
+ +
+
+
+

+ Change website language +

+

+ + Do not switch + +

+
+
+ + + + +
+ + + +
+ +
+
+ +
+
+ +
+

+ The Curse +

+
+
+

+ + Kouzelná země + (E01) +

+ (epizoda) + + +
+ další +
+ + + + + + +
    +
  • +USA Land of Enchantment +
  • +
+
+
+
+ + +
+
+ + + + + + více + + +
+ + + + + +
+
+
+
+
+
+
+
+ 70% + +
+ +
+ + + + Hodnocení a fanklub + + +
+ + +
USA, + 2023, 1 h 1 min + + +
+ + +
+
+
+
+ +
+
+

VOD (1)

+ +
+ +
+ + + + +
+
+

+ Obsahy(1) + + +

+
+
+
+
+ + +

+ Novomanželé Whitney a Asher Siegelovi se rozhodnou natočit pořad pro domácí kutily. + + + (SkyShowtime) + +

+
+ +
+
+
+ + + +
+ + + +
+
+ +
+
+ +
+
+

Recenze (3)

+
+
+
+
+
+
+

SpaceOdyseus 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + Cringe on purpose? Ok, ale moc nevím, co z toho vyleze a jestli to chci zjišťovat v dalších epizodách. + + + + + + () + +

+ + +
+
+ +
+
+
+
+

William_ 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Úvodní hodinka si mě teda získala. Otevírá to spoustu společenských témat a kritiku levičáckých elit, které se snaží hrát na otevřené lidi, ale přitom myslí jen samy na sebe. Tenhle seriál by měli pouštět v Holešovicích v místních podnicích. Nacházím v něm totiž spoustu podobného především v chování a myšlení tamních "elit". + + + + + + () + +

+ + +
+
+

Reklama

+
+
+
+ + + +
+
+ +
+
+

Galerie (42)

+
+ VÍCE +
+
+
+
+ + + +
+ + + +
+
+ + +
+ +
+
+

Reklama

+
+
+
+
+
+

Reklama

+
+
+
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + + + + + + + +`; diff --git a/tests/mocks/series2-episodes.mock.ts b/tests/mocks/series2-episodes.mock.ts new file mode 100644 index 0000000..2df465e --- /dev/null +++ b/tests/mocks/series2-episodes.mock.ts @@ -0,0 +1,1560 @@ +export const serie2EpisodesMock = ` + + + + + + + + The Curse (2023) | ČSFD.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Reklama

+
+
+
+ +
+
+
+

+ Change website language +

+

+ + Do not switch + +

+
+
+ + + + +
+ + + +
+ +
+
+ +
+
+ +
+
+

+ + The Curse + +

+ (seriál) + + + + + + + + +
+
+
+
+ + všechny plakáty + +
+ +
+
+
+
+
+ + + + Trailer + + + + +
+ +
+
+
+
+
+
+ +
+
+
+
+
+ 70% + +
+ +
+ + + + Hodnocení a fanklub + + +
+ + +
USA, + (2023–2024), 8 h 45 min + (Minutáž: 36–69 min) + +
+ + +
+
+
+
+ +
+
+

VOD (1)

+ +
+ +
+ + + +
+
+

+ Epizody(10) +

+
+
+ +
+
+ +
+
+

+ Obsahy(1) + + +

+
+
+
+
+ + +

+ Údajná kletba naruší život novomanželského páru, který se snaží počít dítě a také natáčí nový pořad pro domácí kutily. + + + (SkyShowtime) + +

+
+ +
+
+
+ + + +
+ + + +
+
+
+

Videa (1)

+
+
+
+
+
+
+ + + + Trailer + + + + +
+ +
+
+
+
+
+
+ +
+
+

Recenze (29)

+
+ VÍCE +
+
+
+
+
+
+
+

Janek 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Škoda že to nebyly dvacetiminutovky, 200 minut by tomu slušelo daleko víc, devět hodin je masakr a prvních pět dílu je celkem náročných k ukoukání. Ale kdo ví, zda by poslední díl tak vyzněl. Chápu tvrzení, když Nolan řekl, že něco takového v televizi neviděl. Je to svěží vítr, podivně návyková záležitost. Safdie a Fiedler jsou masakrózní koktejl. + + + + + + () + +

+ + +
+
+ +
+
+
+
+

Devadesát Dva 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + "Should I just go reset this?" "It's fine just let it happen." (added 18.5.2024) Jeden z těch případů, kdy se moje hodnocení odráží od toho, jak engaging je tenhle projekt, spíše než jak mě bavil. Nathana Fieldera a jeho práci neznám vůbec, zato Benny Safdie už je pro mě známý pojem... oba se dali do kupy a dostaly tenhle koncept na show ze situace, která se Nathanovi stala, kletba, kterou mu podobně jako v show přiřkla žebračka, zde malá holka, které nechtěl dát peníze / nebo dal ale jen pro show a chce je zpátky. Christopher Nolan sám mě pak zaskočil v tom, že uváděl Q&A s oběma tvůrci a kde se vyjádřil i v rámci toho, že 'The Curse' mu svojí realitou hodně připomněla 'Twin Peaks', což bylo hodně profound point a celou druhou půlku show, od téhle informace jsem se nemohl vzdát toho lynchovského mysteriózního podivna, se kterým se tahle show až do svého ulítlého závěru táhne. Takže, jak zrekapitulovat něco jako je 'The Curse', kde Nathan tvoří perfektně ten blend toho, jak se pro reality show lidi začnou pitvořit a nakládat se svojí vlastní (for clicks), kde (režisér) Benny Safdie sám má nejvtipnější postavu, režiséra, který se snaží uměle dramatizovat a dělat hroty, aby přitáhl diváky k obrazovkám a který zároveň selhává i jako přítel a dá se označit za nejvíc nepředvídatelný element show, kde Emma Stone hraje skvělou roli, ale jakoby její liberální Whitney hrála na všechny strany, a kde podpantofláčový Nathan už nemůže působit snad ani víc bezcharakterně. A přitom 'The Curse' má svoje momenty, má svoje chvíle, kdy umí chytit za koule, taky má svůj tajemný soundtrack, stejně tak jako používá spousty trefných song voleb: E08, rapování v autě (Dead Prez - Hell Yeah), E10 (Dougieho song v autě: Yo no Huego by Big Sheemba). Závěr je samozřejmě záměrně jedno velké WTF, které má po tom sunutí zanechat dojem, ale dojmy z téhle satiry jsou velmi rozpačité, ale líbí se mi ten engage, je to taková to show, ke které budou mít asi lidi hodně co říct a o které bude lidi bavit žvanit, pokud budou znát hlouběji kontext. Ale třeba mě někdy zpětně napadne k tomu napsat něco chytřejšího, show mě nechává spíše roztříštěného... so, lets get that car music Dougie vibe... + + + + + + () + +

+ + +
+
+

Reklama

+
+
+
+ +
+
+
+
+
+
+
+

M.i.k.e 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + The Curse je sice přiznaná fikce, nicméně i tak zvládne obsahovat spoustu prvků typických pro Fieldrovu tvorbu a v mnoha ohledech je dokáže posouvat ještě mnohem dál. Žanry se tu míchají jak o život a díky tomu je tak tahle série chvilku vztahové drama, chvilku je vtipná, pak zase trapná nebo nepříjemná a celé to rámuje satirický tón beroucí si na paškál současné woke pokrytectví. The Curse rozhodně nesedne všem, ale ten kdo jí dá šanci a přistoupí na Fieldrovu a Safdieho hru, ten si nakonec odnese specifikcý zážitek a je jen na něm jak si ho po překvapivém a povedeném závěru interpretuje…80% + + + + + + () + +

+ + +
+
+ +
+
+
+
+

Oralfabet 

+
+ všechny recenze uživatele + (k tomuto seriálu) + +
+
+ + +

+ + Wow, včera jsem viděl poslední epizodu a pořád ještě zpracovávám své dojmy. Nathan Fielder a Benny Safdie společně stvořili něco naprosto unikátního. Má to v sobě jasně rozpoznatelné prvky jejich předchozích projektů, ale zároveň i něco úplně nového, stěží popsatelného... Je to nepříjemné, trapné, napínavé, tragické, vtipné i děsivé. Je to společenská satira, utahující si z fake woke liberalismu a pokrytectví celebrit na sociálních sítích, dekonstrukce reality TV i reality samotné, situační cringe komedie, Lynchovský surrealistický horor, vztahové drama a Bůh ví, co ještě... Je to padesát různých věcí najednou, ale zároveň soustředěný, koherentní projekt. Čemuž napomáhají i přesné herecké výkony, obzvlášť musím vyzdvihnout Emmu Stone, která mi v roce 2023 potvrdila, že je jednou z nejodvážnějších a nejtalentovanějších současných hereček. Bella z Poor Things je nejspíš její životní rolí, ale Whitney tady taky ztvárnila naprosto mistrně. Nathana musím mimochodem taky pochválit, sice se asi dá říct, že hraje nějakou postavu ve všech svých projektech, ale tady poprvé fakt HRAJE, a dovolím si trvdit, že za Emmou zase až tak výrazně nezaostává. Nesedne to každýmu, na to je to až moc specifické a nepříjemné, ale mě to přišlo absolutně fascinující a snad i geniální. 10/10 + + + + + + () + +

+ + +
+
+ +
+
+
+
+
+
+
+

J*A*S*M 

+
+ všechny recenze uživatele + + +
+
+ + +

+ + Bingnul jsem celou sérii po twitterových WTF ohlasech na poslední část, a převládajícím výsledným pocitem je asi zmatenost spojená s rozmrzelostí. Má to spoustu záblesků briliance, ale zcela divácky uspokojen se necítím. Nejlíp to na mne fungovalo v momentech komediální satiry na virtue signalling, přetvářku na kamery a pokrytectví boháčů, ale těch žánrů a motivů má The Curse mnohem více, přičemž se mi nezdá, že by se všechny dočkaly uspokojivého vyústění. Poslední epizoda je zhruba od půlky fajn full bizár, ale když jí předchází devět hodin relativně při zemi se držícího normálního dramatu ... přijde mi to jako odraz domýšlivosti tvůrců, té stejné domýšlivost, jakou trpí hlavní hrdinovů seriálu. + + + + + + () + +

+ + +
+
+ +
+
+ +
+
+

Galerie (236)

+
+ VÍCE +
+
+
+
+ +
+
+

Zajímavosti (2)

+
+
+
+
+
    +
  • +Seriál byl inspirován incidentem, kdy Nathana Fieldera (Asher Siegel) oslovila žebračka v Los Angeles. Poté, co Fielder odmítl dát ženě peníze, řekla mu: „Proklínám tě.“ Fielder byl jejími slovy tak otřesen, že šel k bankomatu a vybral 20 dolarů. Poté, co dal ženě peníze, zeptal se, zda byla kletba zlomena. Řekla, že ano. + + + (pórek) + + + +
  • +
+
+
+
+
+
    +
  • +Natáčanie prebiehalo v Novom Mexiku v meste Santa Fe a okolí, najmä v bare Dragon Room v Pink Adobe a v historických častiach Loretto Chapel a Santa Fe Plaza. + + + (F2003F) + + + +
  • +
+
+
+
+
+ + +
+ + + +
+
+

Související novinky

+
+
+
+
+
+
+
+
+ + Co dalšího chystá Nolan a jaké filmy si loni oblíbil? + +
+
+

+ Co dalšího chystá Nolan a jaké filmy si loni oblíbil? +

+
+ 01.02.2024 +
+
+
+
+

+ Když jste jeden z nejúspěšnějších a zároveň nejoceňovanějších filmařů světa, máte tu výsadu, že vaše vyjádření ohledně kinematografie sleduje a dá na ně dost široká obec. V nedávné době tak tvůrce… + (více) +

+
+
+
+
+
+
+
+
+
+
+
+ + +
+ +
+
+

Reklama

+
+
+
+
+
+

Reklama

+
+
+
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + + + + + + + + +`; diff --git a/tests/movie.test.ts b/tests/movie.test.ts index b691b68..8e73de9 100644 --- a/tests/movie.test.ts +++ b/tests/movie.test.ts @@ -11,6 +11,7 @@ import { } from '../src/dto/movie'; import { getColor } from '../src/helpers/global.helper'; import { + getEpisodeCode, getLocalizedCreatorLabel, getMovieBoxMovies, getMovieColorRating, @@ -31,7 +32,9 @@ import { getMovieTrivia, getMovieType, getMovieVods, - getMovieYear + getMovieYear, + getSeasonOrEpisodeParent, + getSeriesAndSeasonTitle } from '../src/helpers/movie.helper'; import { movieMock } from './mocks/movie1.html'; import { movieMockBlank } from './mocks/movie2.html'; @@ -621,3 +624,58 @@ describe('Get people', () => { }); }); }); + +describe('Get Series and Season Title', () => { + test('With series and season', () => { + const html = parse('

Series Name - Season 1

'); + const result = getSeriesAndSeasonTitle(html as any); + expect(result).toEqual({ seriesName: 'Series Name', seasonName: 'Season 1' }); + }); + + test('Only series name', () => { + const html = parse('

Movie Name

'); + const result = getSeriesAndSeasonTitle(html as any); + expect(result).toEqual({ seriesName: 'Movie Name', seasonName: null }); + }); + + test('No title element', () => { + const html = parse('
'); + const result = getSeriesAndSeasonTitle(html as any); + expect(result).toEqual({ seriesName: null, seasonName: null }); + }); +}); + +describe('Get Episode Code', () => { + test('With code', () => { + const html = parse('

Episode Name (S01E01)

'); + const result = getEpisodeCode(html as any); + expect(result).toEqual('S01E01'); + }); + + test('Without code', () => { + const html = parse('

Episode Name

'); + const result = getEpisodeCode(html as any); + expect(result).toBeNull(); + }); + + test('No header', () => { + const html = parse('
'); + const result = getEpisodeCode(html as any); + expect(result).toBeNull(); + }); +}); + +describe('Get Season or Episode Parent', () => { + test('No parents but serie provided', () => { + const html = parse('
'); + const serie = { id: 123, name: 'Series' }; + const result = getSeasonOrEpisodeParent(html as any, serie); + expect(result).toEqual({ series: serie, season: null }); + }); + + test('No parents and no serie', () => { + const html = parse('
'); + const result = getSeasonOrEpisodeParent(html as any); + expect(result).toBeNull(); + }); +}); diff --git a/tests/series.test.ts b/tests/series.test.ts new file mode 100644 index 0000000..de47763 --- /dev/null +++ b/tests/series.test.ts @@ -0,0 +1,226 @@ +import { HTMLElement, parse } from 'node-html-parser'; +import { describe, expect, test } from 'vitest'; +import { MovieJsonLd } from '../src/dto/movie'; +import { + getEpisodeCode, + getMovieCreators, + getMovieDescriptions, + getMovieDuration, + getMovieGenres, + getMovieRating, + getMovieType, + getMovieVods, + getMovieYear, + getSeasonOrEpisodeParent, + getSeasonsOrEpisodes, + getSeriesAndSeasonTitle +} from '../src/helpers/movie.helper'; +import { serie1Season1EpisodeMock } from './mocks/series1-season1-episode.mock'; +import { serie1Season1Mock } from './mocks/series1-season1.mock'; +import { serie1SeasonsMock } from './mocks/series1-seasons.mock'; +import { serie2EpisodeMock } from './mocks/series2-episode.mock'; +import { serie2EpisodesMock } from './mocks/series2-episodes.mock'; + +const getPageClasses = (node: HTMLElement): string[] => { + return node.querySelector('.page-content')?.classNames.split(' ') ?? ['']; +}; + +const getAsideNode = (node: HTMLElement): HTMLElement => { + return node.querySelector('.aside-movie-profile') as HTMLElement; +}; + +const getNode = (node: HTMLElement): HTMLElement => { + return node.querySelector('.main-movie-profile') as HTMLElement; +}; + +const getJsonLd = (node: HTMLElement): MovieJsonLd | null => { + const json = node.querySelector('script[type="application/ld+json"]')?.innerText; + try { + return json ? JSON.parse(json) : null; + } catch (e) { + return null; + } +}; + +const getMovie = ( + node: HTMLElement +): { pClasses: string[]; aside: HTMLElement; pNode: HTMLElement; jsonLd: MovieJsonLd | null } => { + return { + pClasses: getPageClasses(node), + aside: getAsideNode(node), + pNode: getNode(node), + jsonLd: getJsonLd(node) + }; +}; + +// Series Pattern 1: Series with Seasons (The Simpsons) +const serie1SeasonsHtml = parse(serie1SeasonsMock); +const { + pNode: serie1SeasonsNode, + aside: serie1SeasonsAside, + jsonLd: serie1SeasonsJsonLd +} = getMovie(serie1SeasonsHtml); + +const serie1Season1Html = parse(serie1Season1Mock); +const { pNode: serie1Season1Node, jsonLd: serie1Season1JsonLd } = getMovie(serie1Season1Html); + +const serie1Season1EpisodeHtml = parse(serie1Season1EpisodeMock); +const { pNode: serie1Season1EpisodeNode, jsonLd: serie1Season1EpisodeJsonLd } = + getMovie(serie1Season1EpisodeHtml); + +// Series Pattern 2: Series with Direct Episodes (The Curse) +const serie2EpisodesHtml = parse(serie2EpisodesMock); +const { + pNode: serie2EpisodesNode, + aside: serie2EpisodesAside, + jsonLd: serie2EpisodesJsonLd +} = getMovie(serie2EpisodesHtml); + +const serie2EpisodeHtml = parse(serie2EpisodeMock); +const { + pNode: serie2EpisodeNode, + aside: serie2EpisodeAside, + jsonLd: serie2EpisodeJsonLd +} = getMovie(serie2EpisodeHtml); + +describe('Get Type', () => { + test('Series 1 Main', () => { + expect(getMovieType(serie1SeasonsNode)).toBe('seriál'); + }); + test('Series 1 Season', () => { + expect(getMovieType(serie1Season1Node)).toBe('série'); + }); + test('Series 1 Episode', () => { + expect(getMovieType(serie1Season1EpisodeNode)).toBe('epizoda'); + }); + test('Series 2 Main', () => { + expect(getMovieType(serie2EpisodesNode)).toBe('seriál'); + }); + test('Series 2 Episode', () => { + expect(getMovieType(serie2EpisodeNode)).toBe('epizoda'); + }); +}); + +describe('Get Seasons or Episodes', () => { + test('Series 1 Main should have seasons', () => { + const seasons = getSeasonsOrEpisodes(serie1SeasonsNode); + expect(seasons).toBeDefined(); + expect(seasons!.length).toBeGreaterThan(0); + expect(seasons![0]).toHaveProperty('name'); + }); + test('Series 1 Season should have episodes', () => { + const episodes = getSeasonsOrEpisodes(serie1Season1Node); + expect(episodes).toBeDefined(); + expect(episodes!.length).toBeGreaterThan(0); + }); + test('Series 2 Main should have episodes directly', () => { + const episodes = getSeasonsOrEpisodes(serie2EpisodesNode); + expect(episodes).toBeDefined(); + expect(episodes!.length).toBeGreaterThan(0); + }); +}); + +describe('Get Series and Season Title', () => { + test('Series 1 Season title extraction', () => { + const result = getSeriesAndSeasonTitle(serie1Season1Node); + expect(result.seriesName).toBe('Simpsonovi'); + expect(result.seasonName).toBe('Série 1'); + }); +}); + +describe('Get Parent', () => { + test('Series 1 Episode parent', () => { + // Assuming title is extracted as Mluvící hlava + const parent = getSeasonOrEpisodeParent(serie1Season1EpisodeNode, { + id: 474220, + name: 'Mluvící hlava' + }); + expect(parent).toBeDefined(); + expect(parent!.series.name).toBe('Simpsonovi'); + expect(parent!.season!.name).toBe('Série 1'); + }); + test('Series 2 Episode parent', () => { + const parent = getSeasonOrEpisodeParent(serie2EpisodeNode, { + id: 1436408, + name: 'Kouzelná země' + }); + expect(parent).toBeDefined(); + expect(parent!.series.name).toBe('The Curse'); + expect(parent!.season).toBeNull(); + }); +}); + +describe('Get Episode Code', () => { + test('Series 1 Episode', () => { + expect(getEpisodeCode(serie1Season1EpisodeNode)).toBe('S01E08'); + }); + test('Series 2 Episode', () => { + expect(getEpisodeCode(serie2EpisodeNode)).toBe('E01'); + }); +}); + +describe('Get Year', () => { + test('Series 1 Main', () => { + expect(getMovieYear(serie1SeasonsJsonLd)).toBe(1989); + }); + test('Series 2 Main', () => { + expect(getMovieYear(serie2EpisodesJsonLd)).toBe(2023); + }); + test('Episode', () => { + expect(getMovieYear(serie2EpisodeJsonLd)).toBe(2023); + }); +}); + +describe('Get Ratings', () => { + test('Series 1 Main', () => { + expect(getMovieRating(serie1SeasonsAside)).toBeGreaterThan(90); + }); + test('Series 2 Main', () => { + expect(getMovieRating(serie2EpisodesAside)).toBeGreaterThan(60); + }); +}); + +describe('Get Creators', () => { + test('Series 1 Main', () => { + const creators = getMovieCreators(serie1SeasonsNode); + expect(creators.directors.length).toBeGreaterThan(0); + }); + test('Series 2 Main', () => { + const creators = getMovieCreators(serie2EpisodesNode); + expect(creators.directors.length).toBeGreaterThan(0); + }); +}); + +describe('Get Genres', () => { + test('Series 1 Main', () => { + expect(getMovieGenres(serie1SeasonsNode)).toContain('Animovaný'); + }); + test('Series 2 Main', () => { + expect(getMovieGenres(serie2EpisodesNode)).toContain('Komedie'); + }); +}); + +describe('Get VOD services', () => { + test('Series 2 Main', () => { + expect(getMovieVods(serie2EpisodesAside).length).toBeGreaterThan(0); + }); +}); + +describe('Get Descriptions', () => { + test('Series 1 Episode', () => { + const desc = getMovieDescriptions(serie1Season1EpisodeNode); + expect(desc.length).toBeGreaterThan(0); + }); + test('Series 2 Main', () => { + expect(getMovieDescriptions(serie2EpisodesNode).length).toBeGreaterThan(0); + }); +}); + +describe('Get Duration', () => { + test('Series 1 Episode', () => { + expect(getMovieDuration(serie1Season1EpisodeJsonLd, serie1Season1EpisodeNode)).toBe(22); + }); + test('Series 2 Episode', () => { + expect(getMovieDuration(serie2EpisodeJsonLd, serie2EpisodeNode)).toBe(61); + }); +});