From 59ea231ddb3dce7d862ef86d3f8e169681c04cd3 Mon Sep 17 00:00:00 2001 From: Bas Rieter Date: Sun, 5 Nov 2023 12:21:21 +0100 Subject: [PATCH] Updated: TV4 Tests. --- tests/channel_tests/channeltest.py | 5 +++- tests/channel_tests/test_chn_tv4se.py | 38 ++++++++++++++++++--------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/tests/channel_tests/channeltest.py b/tests/channel_tests/channeltest.py index 3c43f239b..52354a22d 100644 --- a/tests/channel_tests/channeltest.py +++ b/tests/channel_tests/channeltest.py @@ -44,12 +44,15 @@ def _switch_channel(self, channel_code): self.channel = ChannelIndex.get_register().get_channel(self._channel, self._code) return self.channel - def _test_folder_url(self, url, expected_results=None, exact_results=False, headers=None, retry=1): + def _test_folder_url(self, url, expected_results=None, exact_results=False, headers=None, + retry=1, json=None, data=None): self.assertIsNotNone(self.channel) while retry >= 0: try: item = self._get_media_item(url) + item.postJson = json + item.postData = data item.HttpHeaders.update(headers or {}) items = self.channel.process_folder_list(item) diff --git a/tests/channel_tests/test_chn_tv4se.py b/tests/channel_tests/test_chn_tv4se.py index 42983f95d..527b8ba5b 100644 --- a/tests/channel_tests/test_chn_tv4se.py +++ b/tests/channel_tests/test_chn_tv4se.py @@ -19,33 +19,45 @@ def test_main_list(self): self.assertGreaterEqual(len(items), 5, "Incorrect number of items in mainlist") def test_program_list(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=MediaIndex&variables=%7B%22input%22%3A%20%7B%22letterFilters%22%3A%20%5B%22A%22%2C%20%22B%22%2C%20%22C%22%2C%20%22D%22%2C%20%22E%22%2C%20%22F%22%2C%20%22G%22%2C%20%22H%22%2C%20%22I%22%2C%20%22J%22%2C%20%22K%22%2C%20%22L%22%2C%20%22M%22%2C%20%22N%22%2C%20%22O%22%2C%20%22P%22%2C%20%22Q%22%2C%20%22R%22%2C%20%22S%22%2C%20%22T%22%2C%20%22U%22%2C%20%22V%22%2C%20%22W%22%2C%20%22X%22%2C%20%22Y%22%2C%20%22Z%22%5D%2C%20%22limit%22%3A%20500%2C%20%22offset%22%3A%200%7D%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%22423ba183684c9ea464c94e200696c8f6ec190fe9837f542a672623fa87ef0f4e%22%7D%7D" + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=MediaIndex&query=query%20MediaIndex%28%24input%3A%20MediaIndexListInput%21%2C%20%24genres%3A%20%5BString%21%5D%29%20%7B%20mediaIndex%28genres%3A%20%24genres%29%20%7B%20overview%20%7B%20letterIndex%20%7B%20letter%20totalCount%20%7D%20%7D%20contentList%28input%3A%20%24input%29%20%7B%20__typename%20items%20%7B%20...%20on%20MediaIndexSeriesItem%20%7B%20__typename%20letter%20series%20%7B%20...SeriesFieldsLight%20__typename%20%7D%20%7D%20...%20on%20MediaIndexMovieItem%20%7B%20__typename%20letter%20movie%20%7B%20...MovieFieldsLight%20__typename%20%7D%20%7D%20%7D%20pageInfo%20%7B%20hasMoreForLastLetter%20totalCount%20lastLetter%20nextPageOffset%20%7D%20%7D%20%7D%20%7D%20fragment%20SeriesFieldsLight%20on%20Series%20%7B%20id%20slug%20title%20genres%20mediaClassification%20numberOfAvailableSeasons%20label%20%7B%20...LabelFields%20%7D%20images%20%7B%20cover2x3%20%7B%20...ImageFieldsFull%20%7D%20main16x9Annotated%20%7B%20...ImageFieldsLight%20%7D%20%7D%20parentalRating%20%7B%20...ParentalRatingFields%20%7D%20trailers%20%7B%20mp4%20webm%20%7D%20upsell%20%7B%20tierId%20%7D%20%7D%20fragment%20MovieFieldsLight%20on%20Movie%20%7B%20id%20slug%20title%20genres%20productionYear%20isLiveContent%20productionCountries%20%7B%20name%20%7D%20parentalRating%20%7B%20...ParentalRatingFields%20%7D%20liveEventEnd%20%7B%20isoString%20%7D%20label%20%7B%20...LabelFields%20%7D%20images%20%7B%20cover2x3%20%7B%20...ImageFieldsFull%20%7D%20main16x9Annotated%20%7B%20...ImageFieldsLight%20%7D%20%7D%20playableUntil%20%7B%20readableDistance%28type%3A%20DAYS_LEFT%29%20%7D%20playableFrom%20%7B%20isoString%20humanDateTime%20readableDate%20%7D%20trailers%20%7B%20mp4%20webm%20%7D%20upsell%20%7B%20tierId%20%7D%20%7D%20fragment%20LabelFields%20on%20Label%20%7B%20id%20airtime%20announcement%20recurringBroadcast%20%7D%20fragment%20ImageFieldsFull%20on%20Image%20%7B%20sourceEncoded%20meta%20%7B%20muteBgColor%20%7B%20hex%20%7D%20%7D%20%7D%20fragment%20ImageFieldsLight%20on%20Image%20%7B%20sourceEncoded%20isFallback%20%7D%20fragment%20ParentalRatingFields%20on%20ParentalRating%20%7B%20finland%20%7B%20ageRestriction%20reason%20%7D%20sweden%20%7B%20ageRecommendation%20suitableForChildren%20%7D%20%7D&variables=%7B%22input%22%3A%20%7B%22letterFilters%22%3A%20%5B%22A%22%2C%20%22B%22%2C%20%22C%22%2C%20%22D%22%2C%20%22E%22%2C%20%22F%22%2C%20%22G%22%2C%20%22H%22%2C%20%22I%22%2C%20%22J%22%2C%20%22K%22%2C%20%22L%22%2C%20%22M%22%2C%20%22N%22%2C%20%22O%22%2C%20%22P%22%2C%20%22Q%22%2C%20%22R%22%2C%20%22S%22%2C%20%22T%22%2C%20%22U%22%2C%20%22V%22%2C%20%22W%22%2C%20%22X%22%2C%20%22Y%22%2C%20%22Z%22%5D%2C%20%22limit%22%3A%20100%2C%20%22offset%22%3A%200%7D%7D" self._test_folder_url(url, expected_results=1000) def test_lastest_news(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&variables=%7B%22panelId%22%3A%20%225Rqb0w0SN16A6YHt5Mx8BU%22%2C%20%22limit%22%3A%20500%2C%20%22offset%22%3A%200%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%223ef650feea500555e560903fee7fc06f8276d046ea880c5540282a5341b65985%22%7D%7D" - self._test_folder_url(url, expected_results=10) + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&" + data = {"operationName": "Panel", "query": "query Panel($panelId: ID!, $offset: Int!, $limit: Int!) { panel(id: $panelId) { ... on ContinueWatchingPanel { id } ... on PagePanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { ... on PagePanelPageItem { page { ...PageListFields } } } } } ... on SportEventPanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { sportEvent { ...SportEventFieldsLight } } } } ... on ClipsPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { __typename clip { __typename ...ClipFieldsLight } } } } ... on EpisodesPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { episode { ...EpisodeFields } labelText } } } ... on MediaPanel { __typename id slug title content(input: {offset: $offset, limit: $limit}) { __typename pageInfo { ...PageInfoFields } items { ... on MediaPanelMovieItem { __typename movie { ...MovieFieldsLight __typename } } ... on MediaPanelSeriesItem { __typename series { ...SeriesFieldsLight __typename} } } } } ... on ChannelPanel { id title type content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { channel { ...ChannelFields } } } } } } fragment ImageFieldsFull on Image { sourceEncoded meta { muteBgColor { hex } } } fragment ParentalRatingFields on ParentalRating { finland { ageRestriction reason } sweden { ageRecommendation suitableForChildren } } fragment ImageFieldsLight on Image { sourceEncoded isFallback } fragment VideoFields on Video { id duration { readableShort readableMinutes seconds } isLiveContent access { hasAccess } isDrmProtected } fragment EpisodeFields on Episode { id slug title isLiveContent isStartOverEnabled series { id title slug } images { main16x9 { ...ImageFieldsLight } } liveEventEnd { isoString } playableUntil { readableDistance(type: DAYS_LEFT) humanDateTime } playableFrom { humanDateTime isoString } video { ...VideoFields } upsell { tierId } } fragment LabelFields on Label { id airtime announcement recurringBroadcast } fragment MovieFieldsLight on Movie { id slug title genres productionYear isLiveContent productionCountries { name } parentalRating { ...ParentalRatingFields } liveEventEnd { isoString } label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } playableUntil { readableDistance(type: DAYS_LEFT) } playableFrom { isoString humanDateTime readableDate } trailers { mp4 webm } upsell { tierId } } fragment SportEventFieldsLight on SportEvent { title slug id league round images { main16x9 { ...ImageFieldsLight } brandLogo { ...ImageFieldsLight } } playableFrom { humanDateTime isoString } liveEventEnd { isoString } isLiveContent upsell { tierId } } fragment SeriesFieldsLight on Series { id slug title genres mediaClassification numberOfAvailableSeasons label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } parentalRating { ...ParentalRatingFields } trailers { mp4 webm } upsell { tierId } } fragment ClipFieldsLight on Clip { id slug title clipVideo: video { ...VideoFields } images { main16x9 { ...ImageFieldsLight } } playableFrom { readableDistance } mediaClassification parent { ... on ClipParentSeriesLink { id title } ... on ClipParentMovieLink { id title } } } fragment ChannelFields on Channel { __typename id title description tagline slug type images { logo { ...ImageFieldsLight } main16x9 { ...ImageFieldsLight } } access { hasAccess } epg { end start title } } fragment PageListFields on PageReference { id title images { image16x9 { ...ImageFieldsFull } image4x3 { ...ImageFieldsFull } logo { ...ImageFieldsLight isFallback } } } fragment PageInfoFields on PageInfo { hasNextPage nextPageOffset totalCount }", "variables": {"panelId": "5Rqb0w0SN16A6YHt5Mx8BU", "limit": 100, "offset": 0}} + self._test_folder_url(url, expected_results=10, json=data) def test_recent(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&variables=%7B%22panelId%22%3A%20%221pDPvWRfhEg0wa5SvlP28N%22%2C%20%22limit%22%3A%20500%2C%20%22offset%22%3A%200%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%223ef650feea500555e560903fee7fc06f8276d046ea880c5540282a5341b65985%22%7D%7D" - self._test_folder_url(url, expected_results=10) + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&" + data = {"operationName": "Panel", "query": "query Panel($panelId: ID!, $offset: Int!, $limit: Int!) { panel(id: $panelId) { ... on ContinueWatchingPanel { id } ... on PagePanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { ... on PagePanelPageItem { page { ...PageListFields } } } } } ... on SportEventPanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { sportEvent { ...SportEventFieldsLight } } } } ... on ClipsPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { __typename clip { __typename ...ClipFieldsLight } } } } ... on EpisodesPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { episode { ...EpisodeFields } labelText } } } ... on MediaPanel { __typename id slug title content(input: {offset: $offset, limit: $limit}) { __typename pageInfo { ...PageInfoFields } items { ... on MediaPanelMovieItem { __typename movie { ...MovieFieldsLight __typename } } ... on MediaPanelSeriesItem { __typename series { ...SeriesFieldsLight __typename} } } } } ... on ChannelPanel { id title type content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { channel { ...ChannelFields } } } } } } fragment ImageFieldsFull on Image { sourceEncoded meta { muteBgColor { hex } } } fragment ParentalRatingFields on ParentalRating { finland { ageRestriction reason } sweden { ageRecommendation suitableForChildren } } fragment ImageFieldsLight on Image { sourceEncoded isFallback } fragment VideoFields on Video { id duration { readableShort readableMinutes seconds } isLiveContent access { hasAccess } isDrmProtected } fragment EpisodeFields on Episode { id slug title isLiveContent isStartOverEnabled series { id title slug } images { main16x9 { ...ImageFieldsLight } } liveEventEnd { isoString } playableUntil { readableDistance(type: DAYS_LEFT) humanDateTime } playableFrom { humanDateTime isoString } video { ...VideoFields } upsell { tierId } } fragment LabelFields on Label { id airtime announcement recurringBroadcast } fragment MovieFieldsLight on Movie { id slug title genres productionYear isLiveContent productionCountries { name } parentalRating { ...ParentalRatingFields } liveEventEnd { isoString } label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } playableUntil { readableDistance(type: DAYS_LEFT) } playableFrom { isoString humanDateTime readableDate } trailers { mp4 webm } upsell { tierId } } fragment SportEventFieldsLight on SportEvent { title slug id league round images { main16x9 { ...ImageFieldsLight } brandLogo { ...ImageFieldsLight } } playableFrom { humanDateTime isoString } liveEventEnd { isoString } isLiveContent upsell { tierId } } fragment SeriesFieldsLight on Series { id slug title genres mediaClassification numberOfAvailableSeasons label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } parentalRating { ...ParentalRatingFields } trailers { mp4 webm } upsell { tierId } } fragment ClipFieldsLight on Clip { id slug title clipVideo: video { ...VideoFields } images { main16x9 { ...ImageFieldsLight } } playableFrom { readableDistance } mediaClassification parent { ... on ClipParentSeriesLink { id title } ... on ClipParentMovieLink { id title } } } fragment ChannelFields on Channel { __typename id title description tagline slug type images { logo { ...ImageFieldsLight } main16x9 { ...ImageFieldsLight } } access { hasAccess } epg { end start title } } fragment PageListFields on PageReference { id title images { image16x9 { ...ImageFieldsFull } image4x3 { ...ImageFieldsFull } logo { ...ImageFieldsLight isFallback } } } fragment PageInfoFields on PageInfo { hasNextPage nextPageOffset totalCount }", "variables": {"panelId": "1pDPvWRfhEg0wa5SvlP28N", "limit": 100, "offset": 0}} + self._test_folder_url(url, expected_results=10, json=data) def test_popular(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&variables=%7B%22panelId%22%3A%20%223QnNaigt4Szgkyz8yMU9oF%22%2C%20%22limit%22%3A%20500%2C%20%22offset%22%3A%200%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%223ef650feea500555e560903fee7fc06f8276d046ea880c5540282a5341b65985%22%7D%7D" - self._test_folder_url(url, expected_results=10) + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Panel&" + data = {"operationName": "Panel", "query": "query Panel($panelId: ID!, $offset: Int!, $limit: Int!) { panel(id: $panelId) { ... on ContinueWatchingPanel { id } ... on PagePanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { ... on PagePanelPageItem { page { ...PageListFields } } } } } ... on SportEventPanel { id content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { sportEvent { ...SportEventFieldsLight } } } } ... on ClipsPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { __typename clip { __typename ...ClipFieldsLight } } } } ... on EpisodesPanel { id title content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { episode { ...EpisodeFields } labelText } } } ... on MediaPanel { __typename id slug title content(input: {offset: $offset, limit: $limit}) { __typename pageInfo { ...PageInfoFields } items { ... on MediaPanelMovieItem { __typename movie { ...MovieFieldsLight __typename } } ... on MediaPanelSeriesItem { __typename series { ...SeriesFieldsLight __typename} } } } } ... on ChannelPanel { id title type content(input: {offset: $offset, limit: $limit}) { pageInfo { ...PageInfoFields } items { channel { ...ChannelFields } } } } } } fragment ImageFieldsFull on Image { sourceEncoded meta { muteBgColor { hex } } } fragment ParentalRatingFields on ParentalRating { finland { ageRestriction reason } sweden { ageRecommendation suitableForChildren } } fragment ImageFieldsLight on Image { sourceEncoded isFallback } fragment VideoFields on Video { id duration { readableShort readableMinutes seconds } isLiveContent access { hasAccess } isDrmProtected } fragment EpisodeFields on Episode { id slug title isLiveContent isStartOverEnabled series { id title slug } images { main16x9 { ...ImageFieldsLight } } liveEventEnd { isoString } playableUntil { readableDistance(type: DAYS_LEFT) humanDateTime } playableFrom { humanDateTime isoString } video { ...VideoFields } upsell { tierId } } fragment LabelFields on Label { id airtime announcement recurringBroadcast } fragment MovieFieldsLight on Movie { id slug title genres productionYear isLiveContent productionCountries { name } parentalRating { ...ParentalRatingFields } liveEventEnd { isoString } label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } playableUntil { readableDistance(type: DAYS_LEFT) } playableFrom { isoString humanDateTime readableDate } trailers { mp4 webm } upsell { tierId } } fragment SportEventFieldsLight on SportEvent { title slug id league round images { main16x9 { ...ImageFieldsLight } brandLogo { ...ImageFieldsLight } } playableFrom { humanDateTime isoString } liveEventEnd { isoString } isLiveContent upsell { tierId } } fragment SeriesFieldsLight on Series { id slug title genres mediaClassification numberOfAvailableSeasons label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } parentalRating { ...ParentalRatingFields } trailers { mp4 webm } upsell { tierId } } fragment ClipFieldsLight on Clip { id slug title clipVideo: video { ...VideoFields } images { main16x9 { ...ImageFieldsLight } } playableFrom { readableDistance } mediaClassification parent { ... on ClipParentSeriesLink { id title } ... on ClipParentMovieLink { id title } } } fragment ChannelFields on Channel { __typename id title description tagline slug type images { logo { ...ImageFieldsLight } main16x9 { ...ImageFieldsLight } } access { hasAccess } epg { end start title } } fragment PageListFields on PageReference { id title images { image16x9 { ...ImageFieldsFull } image4x3 { ...ImageFieldsFull } logo { ...ImageFieldsLight isFallback } } } fragment PageInfoFields on PageInfo { hasNextPage nextPageOffset totalCount }", "variables": {"panelId": "3QnNaigt4Szgkyz8yMU9oF", "limit": 100, "offset": 0}} + self._test_folder_url(url, expected_results=10, json=data) def test_categories(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=PageList&variables=%7B%22pageListId%22%3A%20%22categories%22%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%2258da321b8e31df2b746f1d1f374151a450a4c24bda6415182fe81551c90e7d25%22%7D%7D" - self._test_folder_url(url, expected_results=10) + # url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=PageList&variables=%7B%22pageListId%22%3A%20%22categories%22%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%2258da321b8e31df2b746f1d1f374151a450a4c24bda6415182fe81551c90e7d25%22%7D%7D" + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=PageList&" + data = {"operationName": "PageList", "query": "query PageList($pageListId: ID!) { pageList(id: $pageListId) { id content { ... on PageReferenceItem { pageReference { ...PageListFields __typename } __typename } ... on StaticPageItem { staticPage { id title type images { image4x3 { ...ImageFieldsFull __typename } __typename } __typename } __typename } __typename } __typename }} fragment PageListFields on PageReference { id title images { image16x9 { ...ImageFieldsFull } image4x3 { ...ImageFieldsFull } logo { ...ImageFieldsLight isFallback } } } fragment ImageFieldsFull on Image { sourceEncoded meta { muteBgColor { hex } } } fragment ImageFieldsLight on Image { sourceEncoded isFallback }", "variables": {"pageListId": "categories"}} + self._test_folder_url(url, expected_results=10, json=data) + + @unittest.skip("Requires login") + def test_seasons(self): + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=ContentDetailsPage&query=query%20ContentDetailsPage%28%24mediaId%3A%20ID%21%2C%20%24panelsInput%3A%20CdpPanelsInput%21%29%20%7B%20media%28id%3A%20%24mediaId%29%20%7B%20...%20on%20SportEvent%20%7B%20__typename%20id%20slug%20title%20league%20arena%20commentators%20country%20round%20season%20inStudio%20isLiveContent%20isStartOverEnabled%20humanCallToAction%20editorialInfoText%20synopsis%20%7B%20brief%20long%20%7D%20trailers%20%7B%20...TrailerFields%20%7D%20playableFrom%20%7B%20humanDateTime%20isoString%20readableDate%20%7D%20playableUntil%20%7B%20readableDate%20%7D%20liveEventEnd%20%7B%20isoString%20%7D%20images%20%7B%20poster2x3%20%7B%20...ImageFieldsFull%20%7D%20main16x9%20%7B%20...ImageFieldsFull%20%7D%20logo%20%7B%20...ImageFieldsLight%20%7D%20brandLogo%20%7B%20...ImageFieldsLight%20%7D%20%7D%20upsell%20%7B%20tierId%20%7D%20%7D%20...%20on%20Movie%20%7B%20__typename%20id%20slug%20title%20genres%20humanCallToAction%20isPollFeatureEnabled%20productionYear%20isLiveContent%20isStartOverEnabled%20liveEventEnd%20%7B%20isoString%20%7D%20productionCountries%20%7B%20countryCode%20name%20%7D%20playableFrom%20%7B%20isoString%20readableDate%20humanDateTime%20readableDistance%20%7D%20playableUntil%20%7B%20isoString%20readableDate%20%7D%20video%20%7B%20...VideoFields%20%7D%20parentalRating%20%7B%20...ParentalRatingFields%20%7D%20credits%20%7B%20...MovieCreditsFields%20%7D%20images%20%7B%20poster2x3%20%7B%20...ImageFieldsFull%20%7D%20main16x9%20%7B%20...ImageFieldsFull%20%7D%20logo%20%7B%20...ImageFieldsLight%20%7D%20brandLogo%20%7B%20...ImageFieldsLight%20%7D%20%7D%20synopsis%20%7B%20brief%20long%20%7D%20trailers%20%7B%20...TrailerFields%20%7D%20label%20%7B%20...LabelFields%20%7D%20panels%28input%3A%20%24panelsInput%29%20%7B%20...CdpPanelsFields%20%7D%20hasPanels%20editorialInfoText%20upsell%20%7B%20tierId%20%7D%20%7D%20...%20on%20Series%20%7B%20__typename%20id%20slug%20title%20numberOfAvailableSeasons%20genres%20isPollFeatureEnabled%20upcomingEpisode%20%7B%20...UpcomingEpisodeFields%20%7D%20trailers%20%7B%20...TrailerFields%20%7D%20parentalRating%20%7B%20...ParentalRatingFields%20%7D%20credits%20%7B%20...SeriesCreditsFields%20%7D%20images%20%7B%20poster2x3%20%7B%20...ImageFieldsFull%20%7D%20main16x9%20%7B%20...ImageFieldsFull%20%7D%20logo%20%7B%20...ImageFieldsLight%20%7D%20brandLogo%20%7B%20...ImageFieldsLight%20%7D%20%7D%20synopsis%20%7B%20brief%20long%20%7D%20allSeasonLinks%20%7B%20__typename%20seasonId%20title%20numberOfEpisodes%20%7D%20label%20%7B%20...LabelFields%20%7D%20panels%28input%3A%20%24panelsInput%29%20%7B%20...CdpPanelsFields%20%7D%20hasPanels%20editorialInfoText%20upsell%20%7B%20tierId%20%7D%20%7D%20%7D%20%7D%20fragment%20TrailerFields%20on%20Trailers%20%7B%20mp4%20webm%20%7D%20fragment%20ImageFieldsFull%20on%20Image%20%7B%20sourceEncoded%20meta%20%7B%20muteBgColor%20%7B%20hex%20%7D%20%7D%20%7D%20fragment%20ImageFieldsLight%20on%20Image%20%7B%20sourceEncoded%20isFallback%20%7D%20fragment%20VideoFields%20on%20Video%20%7B%20id%20duration%20%7B%20readableShort%20readableMinutes%20seconds%20%7D%20isLiveContent%20access%20%7B%20hasAccess%20%7D%20isDrmProtected%20%7D%20fragment%20ParentalRatingFields%20on%20ParentalRating%20%7B%20finland%20%7B%20ageRestriction%20reason%20%7D%20sweden%20%7B%20ageRecommendation%20suitableForChildren%20%7D%20%7D%20fragment%20MovieCreditsFields%20on%20MovieCredits%20%7B%20actors%20%7B%20characterName%20name%20type%20%7D%20directors%20%7B%20name%20type%20%7D%20%7D%20fragment%20LabelFields%20on%20Label%20%7B%20id%20airtime%20announcement%20recurringBroadcast%20%7D%20fragment%20CdpPanelsFields%20on%20CdpPanels%20%7B%20items%20%7B%20...%20on%20ClipsPanel%20%7B%20id%20title%20%7D%20%7D%20%7D%20fragment%20UpcomingEpisodeFields%20on%20UpcomingEpisode%20%7B%20id%20title%20seasonTitle%20playableFrom%20%7B%20humanDateTime%20isoString%20readableDateShort%20%7D%20image%20%7B%20main16x9%20%7B%20...ImageFieldsLight%20%7D%20%7D%20upsell%20%7B%20tierId%20%7D%20%7D%20%20fragment%20SeriesCreditsFields%20on%20SeriesCredits%20%7B%20directors%20%7B%20name%20type%20%7D%20hosts%20%7B%20name%20type%20%7D%20actors%20%7B%20characterName%20name%20type%20%7D%20%7D&variables=%7B%22mediaId%22%3A%20%22fbe386fc49d06efd7ee1%22%2C%20%22panelsInput%22%3A%20%7B%22offset%22%3A%200%2C%20%22limit%22%3A%2020%7D%7D" + self._test_folder_url(url, expected_results=4) def test_season_content_listing(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=SeasonEpisodes&variables=%7B%22seasonId%22%3A%20%224952da9781c046017460%22%2C%20%22input%22%3A%20%7B%22limit%22%3A%20100%2C%20%22offset%22%3A%200%7D%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%229f069a1ce297d68a0b4a3d108142919fb6d12827f35fc71b03976a251e239796%22%7D%7D" - self._test_folder_url(url, expected_results=5) + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=SeasonEpisodes&" + data = {"operationName": "SeasonEpisodes", "query": "query SeasonEpisodes($input: SeasonEpisodesInput!, $seasonId: ID!) { season(id: $seasonId) { id numberOfEpisodes episodes(input: $input) { initialSortOrder pageInfo { ...PageInfoFields } items { __typename ...EpisodeFieldsFull } } } } fragment PageInfoFields on PageInfo { hasNextPage nextPageOffset totalCount } fragment EpisodeFieldsFull on Episode { ...EpisodeFields synopsis { medium } parentalRating { ...ParentalRatingFields } upsell { tierId } } fragment EpisodeFields on Episode { id slug title isLiveContent isStartOverEnabled series { id title slug } images { main16x9 { ...ImageFieldsLight } } liveEventEnd { isoString } playableUntil { readableDistance(type: DAYS_LEFT) humanDateTime } playableFrom { humanDateTime isoString } video { ...VideoFields } upsell { tierId } } fragment ParentalRatingFields on ParentalRating { finland { ageRestriction reason } sweden { ageRecommendation suitableForChildren } } fragment ImageFieldsLight on Image { sourceEncoded isFallback } fragment VideoFields on Video { id duration { readableShort readableMinutes seconds } isLiveContent access { hasAccess } isDrmProtected }", "variables": {"seasonId": "c0a98773088605ce81da", "input": {"limit": 100, "offset": 0}}} + self._test_folder_url(url, expected_results=5, json=data) @unittest.skip(reason="Requires Login") def test_list_category_content(self): - url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Page&variables=%7B%22pageId%22%3A%20%22dokument%C3%A4rer%22%2C%20%22input%22%3A%20%7B%22limit%22%3A%20100%2C%20%22offset%22%3A%200%7D%7D&extensions=%7B%22persistedQuery%22%3A%20%7B%22version%22%3A%201%2C%20%22sha256Hash%22%3A%20%22a30fb04a7dbabeaf3b08f66134c6ac1f1e4980de1f21024fa755d752608e6ad9%22%7D%7D" - self._test_folder_url(url, expected_results=5) + url = "https://client-gateway.tv4.a2d.tv/graphql?operationName=Page&" + data = {"operationName": "Page", "query": "query Page($pageId: ID!, $input: PageContentInput!) { page(id: $pageId) { id title content(input: $input) { pageInfo { ...PageInfoFields } panels { __typename ... on TiersPanel { __typename id title detailed } ... on ContinueWatchingPanel { __typename id title } ... on MediaPanel { __typename id slug title displayHint { mediaPanelImageRatio } } ... on SportEventPanel { __typename id title } ... on ClipsPanel { __typename id title } ... on EpisodesPanel { __typename id title } ... on LivePanel { __typename id title } ... on PagePanel { __typename id title } ... on ChannelPanel { __typename id title type } ... on ThemePanel { __typename ...ThemePanelFields } ... on SinglePanel { __typename ...SinglePanelFields } ... on TiersPanel { __typename id title } } } } } fragment PageInfoFields on PageInfo { hasNextPage nextPageOffset totalCount } fragment ThemePanelFields on ThemePanel { id title pitch hexColor images { image16x9 { ...ImageFieldsFull } } link { ... on ThemePanelSeriesLink { series { id slug genres numberOfAvailableSeasons parentalRating { ...ParentalRatingFields } images { brandLogo { ...ImageFieldsLight } } upsell { tierId } } } ... on ThemePanelMovieLink { movie { id slug genres productionCountries { countryCode name } productionYear parentalRating { ...ParentalRatingFields } images { brandLogo { ...ImageFieldsLight } } upsell { tierId } } } ... on ThemePanelEpisodeLink { episode { id slug upsell { tierId } } } ... on ThemePanelClipLink { clip { id slug } } ... on ThemePanelPageLink { page { id } } ... on ThemePanelUrlsLink { webUrl } ... on ThemePanelSportEventLink { sportEvent { id slug arena league round playableFrom { humanDateTime isoString readableDate } images { brandLogo { ...ImageFieldsLight } } upsell { tierId } } } } themePanelLinkText: linkText showMetadataForLink subtitle trailers { ...TrailerFields } showUpsellLabel } fragment SinglePanelFields on SinglePanel { id secondaryLinkText images { image16x9 { ...ImageFieldsFull } image2x3 { ...ImageFieldsFull } brandLogo { ...ImageFieldsLight } } link { __typename ... on SinglePanelPageLink { page { id } } ... on SinglePanelSportEventLink { sportEvent { ...SportEventFieldsLight } } ... on SinglePanelSeriesLink { series { ...SeriesFieldsLight } } ... on SinglePanelMovieLink { movie { ...MovieFieldsLight } } ... on SinglePanelEpisodeLink { episode { ...EpisodeFields } } ... on SinglePanelClipLink { clip { ...ClipFieldsLight } } ... on SinglePanelChannelLink { channel { ...ChannelFields } } } trailers { ...TrailerFields } linkText title pitch shortPitch } fragment ImageFieldsFull on Image { sourceEncoded meta { muteBgColor { hex } } } fragment ParentalRatingFields on ParentalRating { finland { ageRestriction reason } sweden { ageRecommendation suitableForChildren } } fragment ImageFieldsLight on Image { sourceEncoded isFallback } fragment TrailerFields on Trailers { mp4 webm } fragment SportEventFieldsLight on SportEvent { title slug id league round images { main16x9 { ...ImageFieldsLight } brandLogo { ...ImageFieldsLight } } playableFrom { humanDateTime isoString } liveEventEnd { isoString } isLiveContent upsell { tierId } } fragment SeriesFieldsLight on Series { id slug title genres mediaClassification numberOfAvailableSeasons label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } parentalRating { ...ParentalRatingFields } trailers { mp4 webm } upsell { tierId } } fragment MovieFieldsLight on Movie { id slug title genres productionYear isLiveContent productionCountries { name } parentalRating { ...ParentalRatingFields } liveEventEnd { isoString } label { ...LabelFields } images { cover2x3 { ...ImageFieldsFull } main16x9Annotated { ...ImageFieldsLight } } playableUntil { readableDistance(type: DAYS_LEFT) } playableFrom { isoString humanDateTime readableDate } trailers { mp4 webm } upsell { tierId } } fragment EpisodeFields on Episode { id slug title isLiveContent isStartOverEnabled series { id title slug } images { main16x9 { ...ImageFieldsLight } } liveEventEnd { isoString } playableUntil { readableDistance(type: DAYS_LEFT) humanDateTime } playableFrom { humanDateTime isoString } video { ...VideoFields } upsell { tierId } } fragment ClipFieldsLight on Clip { id slug title clipVideo: video { ...VideoFields } images { main16x9 { ...ImageFieldsLight } } playableFrom { readableDistance } mediaClassification parent { ... on ClipParentSeriesLink { id title } ... on ClipParentMovieLink { id title } } } fragment ChannelFields on Channel { __typename id title description tagline slug type images { logo { ...ImageFieldsLight } main16x9 { ...ImageFieldsLight } } access { hasAccess } epg { end start title } } fragment LabelFields on Label { id airtime announcement recurringBroadcast } fragment VideoFields on Video { id duration { readableShort readableMinutes seconds } isLiveContent access { hasAccess } isDrmProtected }", "variables": {"pageId": "sport", "input": {"limit": 100, "offset": 0}}} + self._test_folder_url(url, expected_results=5, json=data) @unittest.skip(reason="Requires Login") def test_video_playback(self):