From 4b655fc9eda77cb606ba18f44683f15c241f054a Mon Sep 17 00:00:00 2001 From: "Phyks (Lucas Verney)" Date: Tue, 5 Mar 2024 11:29:17 +0100 Subject: [PATCH] Move to Justwatch newer API/graphql --- public/index.html | 427 +++++++++++++++++++++++++++------------------- 1 file changed, 251 insertions(+), 176 deletions(-) diff --git a/public/index.html b/public/index.html index 6316af5..504a6fc 100644 --- a/public/index.html +++ b/public/index.html @@ -99,7 +99,7 @@

{{ availableLocales[locale] }}

None

@@ -110,7 +110,7 @@ var JUSTWATCH_API_DOMAIN = 'https://apis.justwatch.com'; var checkedLocales = JSON.parse(localStorage.getItem('checkedLocales')); if (!checkedLocales) { - checkedLocales = ['fr_FR', 'en_AU', 'en_CA', 'de_DE', 'pl_PL', 'en_SG', 'en_GB']; + checkedLocales = ['FR', 'AU', 'CA', 'DE', 'PL', 'SG', 'GB']; } var app = new Vue({ @@ -127,138 +127,138 @@ var app = new Vue({ data: { checkedLocales: checkedLocales, availableCountries: { - "Afghanistan": "ps_AF", - "Albania": "sq_AL", - "Algeria": "ar_DZ", - "Andorra": "ca_AD", - "Antigua And Barbuda": "en_AG", - "Argentina": "es_AR", - "Armenia": "hy_AM", - "Aruba": "nl_AW", - "Australia": "en_AU", - "Austria": "de_AT", - "Azerbaijan": "az_AZ", - "Bahrain": "ar_BH", - "Bangladesh": "bn_BD", - "Belarus": "be_BY", - "Belgium": "fr_BE", - "Bhutan": "dz_BT", - "Bolivia": "es_BO", - "Bosnia And Herzegovina": "bs_BA", - "Botswana": "en_BW", - "Brazil": "pt_BR", - "Bulgaria": "bg_BG", - "Cambodia": "km_KH", - "Canada": "en_CA", - "Chile": "es_CL", - "China": "zh_CN", - "Colombia": "es_CO", - "Costa Rica": "es_CR", - "Croatia": "hr_HR", - "Cyprus": "el_CY", - "Czech Republic": "cs_CZ", - "Denmark": "da_DK", - "Djibouti": "so_DJ", - "Dominican Republic": "es_DO", - "Ecuador": "es_EC", - "Egypt": "ar_EG", - "El Salvador": "es_SV", - "Eritrea": "tig_ER", - "Estonia": "et_EE", - "Ethiopia": "am_ET", - "Faroe Islands": "fo_FO", - "Finland": "fi_FI", - "France": "fr_FR", - "Georgia": "ka_GE", - "Germany": "de_DE", - "Greece": "el_GR", - "Greenland": "kl_GL", - "Guatemala": "es_GT", - "Haiti": "ht_HT", - "Honduras": "es_HN", - "Hong Kong": "en_HK", - "Hungary": "hu_HU", - "Iceland": "is_IS", - "India": "en_IN", - "Indonesia": "id_ID", - "Iran, Islamic Republic Of": "fa_IR", - "Iraq": "ar_IQ", - "Ireland": "en_IE", - "Israel": "he_IL", - "Italy": "it_IT", - "Japan": "ja_JP", - "Jordan": "ar_JO", - "Kazakhstan": "kk_KZ", - "Kenya": "om_KE", - "Korea, Republic Of": "ko_KR", - "Kuwait": "ar_KW", - "Kyrgyzstan": "ky_KG", - "Latvia": "lv_LV", - "Lebanon": "ar_LB", - "Libyan Arab Jamahiriya": "ar_LY", - "Liechtenstein": "de_LI", - "Lithuania": "lt_LT", - "Luxembourg": "fr_LU", - "Macedonia": "mk_MK", - "Madagascar": "mg_MG", - "Malaysia": "ms_MY", - "Maldives": "dv_MV", - "Malta": "mt_MT", - "Mexico": "es_MX", - "Mongolia": "mn_MN", - "Morocco": "ar_MA", - "Myanmar": "my_MM", - "Nepal": "ne_NP", - "Netherlands": "nl_NL", - "Netherlands Antilles": "pap_AN", - "New Zealand": "en_NZ", - "Nicaragua": "es_NI", - "Nigeria": "en_NG", - "Norway": "no_NO", - "Oman": "ar_OM", - "Pakistan": "pa_PK", - "Panama": "es_PA", - "Paraguay": "es_PY", - "Peru": "es_PE", - "Philippines": "en_PH", - "Poland": "pl_PL", - "Portugal": "pt_PT", - "Puerto Rico": "es_PR", - "Qatar": "ar_QA", - "Romania": "ro_RO", - "Russian Federation": "ru_RU", - "Rwanda": "rw_RW", - "Saudi Arabia": "ar_SA", - "Senegal": "wo_SN", - "Serbia And Montenegro": "sr_CS", - "Singapore": "en_SG", - "Slovakia": "sk_SK", - "Slovenia": "sl_SI", - "Somalia": "so_SO", - "South Africa": "af_ZA", - "Spain": "es_ES", - "Sri Lanka": "si_LK", - "Sudan": "ar_SD", - "Sweden": "sv_SE", - "Switzerland": "fr_CH", - "Syrian Arab Republic": "ar_SY", - "Taiwan": "zh_TW", - "Tajikistan": "tg_TJ", - "Thailand": "th_TH", - "Tunisia": "ar_TN", - "Turkey": "tr_TR", - "Turkmenistan": "tk_TM", - "Uganda": "lg_UG", - "Ukraine": "uk_UA", - "United Arab Emirates": "ar_AE", - "United Kingdom": "en_GB", - "United States": "en_US", - "Uruguay": "es_UY", - "Uzbekistan": "uz_UZ", - "Venezuela": "es_VE", - "Viet Nam": "vi_VN", - "Yemen": "ar_YE", - "Zimbabwe": "en_ZW" + "Afghanistan": "AF", + "Albania": "AL", + "Algeria": "DZ", + "Andorra": "AD", + "Antigua And Barbuda": "AG", + "Argentina": "AR", + "Armenia": "AM", + "Aruba": "AW", + "Australia": "AU", + "Austria": "AT", + "Azerbaijan": "AZ", + "Bahrain": "BH", + "Bangladesh": "BD", + "Belarus": "BY", + "Belgium": "BE", + "Bhutan": "BT", + "Bolivia": "BO", + "Bosnia And Herzegovina": "BA", + "Botswana": "BW", + "Brazil": "BR", + "Bulgaria": "BG", + "Cambodia": "KH", + "Canada": "CA", + "Chile": "CL", + "China": "CN", + "Colombia": "CO", + "Costa Rica": "CR", + "Croatia": "HR", + "Cyprus": "CY", + "Czech Republic": "CZ", + "Denmark": "DK", + "Djibouti": "DJ", + "Dominican Republic": "DO", + "Ecuador": "EC", + "Egypt": "EG", + "El Salvador": "SV", + "Eritrea": "tER", + "Estonia": "EE", + "Ethiopia": "ET", + "Faroe Islands": "FO", + "Finland": "FI", + "France": "FR", + "Georgia": "GE", + "Germany": "DE", + "Greece": "GR", + "Greenland": "GL", + "Guatemala": "GT", + "Haiti": "HT", + "Honduras": "HN", + "Hong Kong": "HK", + "Hungary": "HU", + "Iceland": "IS", + "India": "IN", + "Indonesia": "ID", + "Iran, Islamic Republic Of": "IR", + "Iraq": "IQ", + "Ireland": "IE", + "Israel": "IL", + "Italy": "IT", + "Japan": "JP", + "Jordan": "JO", + "Kazakhstan": "KZ", + "Kenya": "KE", + "Korea, Republic Of": "KR", + "Kuwait": "KW", + "Kyrgyzstan": "KG", + "Latvia": "LV", + "Lebanon": "LB", + "Libyan Arab Jamahiriya": "LY", + "Liechtenstein": "LI", + "Lithuania": "LT", + "Luxembourg": "LU", + "Macedonia": "MK", + "Madagascar": "MG", + "Malaysia": "MY", + "Maldives": "MV", + "Malta": "MT", + "Mexico": "MX", + "Mongolia": "MN", + "Morocco": "MA", + "Myanmar": "MM", + "Nepal": "NP", + "Netherlands": "NL", + "Netherlands Antilles": "pAN", + "New Zealand": "NZ", + "Nicaragua": "NI", + "Nigeria": "NG", + "Norway": "NO", + "Oman": "OM", + "Pakistan": "PK", + "Panama": "PA", + "Paraguay": "PY", + "Peru": "PE", + "Philippines": "PH", + "Poland": "PL", + "Portugal": "PT", + "Puerto Rico": "PR", + "Qatar": "QA", + "Romania": "RO", + "Russian Federation": "RU", + "Rwanda": "RW", + "Saudi Arabia": "SA", + "Senegal": "SN", + "Serbia And Montenegro": "CS", + "Singapore": "SG", + "Slovakia": "SK", + "Slovenia": "SI", + "Somalia": "SO", + "South Africa": "ZA", + "Spain": "ES", + "Sri Lanka": "LK", + "Sudan": "SD", + "Sweden": "SE", + "Switzerland": "CH", + "Syrian Arab Republic": "SY", + "Taiwan": "TW", + "Tajikistan": "TJ", + "Thailand": "TH", + "Tunisia": "TN", + "Turkey": "TR", + "Turkmenistan": "TM", + "Uganda": "UG", + "Ukraine": "UA", + "United Arab Emirates": "AE", + "United Kingdom": "GB", + "United States": "US", + "Uruguay": "UY", + "Uzbekistan": "UZ", + "Venezuela": "VE", + "Viet Nam": "VN", + "Yemen": "YE", + "Zimbabwe": "ZW" }, error: null, title: '', @@ -269,25 +269,45 @@ var app = new Vue({ }, methods: { search() { - fetch(`${JUSTWATCH_API_DOMAIN}/content/titles/fr_FR/popular?language=fr&body={"page_size":20,"page":1,"query":"${this.title}","content_types":["show","movie"]}`, { credentials : "include" }) + fetch( + `${JUSTWATCH_API_DOMAIN}/graphql`, + { + method: 'POST', + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + "operationName": "GetSuggestedTitles", + "variables": { + "country": "FR", + "language": "fr", + "first": 4, + "filter": {"searchQuery": this.title} + }, + "query": "query GetSuggestedTitles($country: Country!, $language: Language!, $first: Int!, $filter: TitleFilter) { popularTitles(country: $country, first: $first, filter: $filter) { edges { node { ...SuggestedTitle __typename } __typename } __typename }}fragment SuggestedTitle on MovieOrShow { id objectType objectId content(country: $country, language: $language) { fullPath title originalReleaseYear posterUrl fullPath __typename } watchNowOffer(country: $country, platform: WEB) { id standardWebURL package { id packageId __typename } __typename } offers(country: $country, platform: WEB) { monetizationType presentationType standardWebURL package { id packageId __typename } id __typename } __typename}", + }), + credentials : "include", + } + ) .then(response => response.json()) .then(response => { this.error = null; - if (!response.items || response.items.length == 0) { + if (!response.data.popularTitles.edges || response.data.popularTitles.length == 0) { this.error = 'Not found' return; } - this.searchItems = response.items.map((item) => { + this.searchItems = response.data.popularTitles.edges.map((item) => { var poster = null; - if (item['poster']) { - poster = item['poster'].replace('{profile}', 's276'); + if (item.node.content.posterUrl) { + poster = item.node.content.posterUrl.replace('{profile}', 's276'); } return { - id: item.id, - title: item.title, - type: item.object_type, - poster_url: `https://images.justwatch.com${poster}` + id: item.node.id, + title: item.node.content.title, + type: item.node.objectType, + poster_url: `https://images.justwatch.com${poster}`, + fullPath: item.node.content.fullPath, }; }); @@ -307,29 +327,60 @@ var app = new Vue({ }, preloadItem(index) { var searchItem = this.searchItems[index]; - fetch(`${JUSTWATCH_API_DOMAIN}/content/titles/${searchItem.type}/${searchItem.id}/locale/fr_FR?language=fr`, { credentials : "include" }) - .then(response => response.json()) - .then(response => { - this.seasons = {}; - if (response.seasons && response.seasons.length > 0) { - this.seasons = response.seasons.map((item) => { - var poster = null; - if (item['poster']) { - poster = item['poster'].replace('{profile}', 's276'); + fetch( + `${JUSTWATCH_API_DOMAIN}/graphql`, + { + method: 'POST', + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + "operationName": "GetUrlTitleDetails", + "variables": { + "platform": "WEB", + "fullPath": searchItem.fullPath, + "language": "fr", + "country": "FR", + "episodeMaxLimit": 20, + "allowSponsoredRecommendations": { + "appId": "3.8.2-webapp#dec565e", + "country": "FR", + "language": "fr", + "pageType": "VIEW_TITLE_DETAIL", + "placement": "DETAIL_PAGE", + "platform": "WEB", + "supportedObjectTypes": ["MOVIE", "SHOW", "GENERIC_TITLE_LIST"], + "supportedFormats": ["IMAGE", "VIDEO"] } - return { - id: item.id, - title: item.title, - type: item.object_type, - poster_url: `https://images.justwatch.com${poster}` - }; - }); - this.step += 1; - } else { - this.step += 1; - this.loadItem(index, false); - } - }); + }, + "query": "query GetUrlTitleDetails($fullPath: String!, $country: Country!, $language: Language!, $episodeMaxLimit: Int, $platform: Platform! = WEB, $allowSponsoredRecommendations: SponsoredRecommendationsInput, $format: ImageFormat, $backdropProfile: BackdropProfile) {\n urlV2(fullPath: $fullPath) {\n id\n metaDescription\n metaKeywords\n metaRobots\n metaTitle\n heading1\n heading2\n htmlContent\n node {\n id\n __typename\n ... on MovieOrShowOrSeason {\n plexPlayerOffers: offers(\n country: $country\n platform: $platform\n filter: {packages: [\"pxp\"]}\n ) {\n id\n standardWebURL\n package {\n id\n packageId\n clearName\n technicalName\n shortName\n __typename\n }\n __typename\n }\n disneyOffersCount: offerCount(\n country: $country\n platform: $platform\n filter: {packages: [\"dnp\"]}\n )\n objectType\n objectId\n offerCount(country: $country, platform: $platform)\n offers(country: $country, platform: $platform) {\n monetizationType\n elementCount\n package {\n id\n packageId\n clearName\n __typename\n }\n __typename\n }\n watchNowOffer(country: $country, platform: $platform) {\n id\n standardWebURL\n __typename\n }\n promotedBundles(country: $country, platform: $platform) {\n promotionUrl\n __typename\n }\n availableTo(country: $country, platform: $platform) {\n availableCountDown(country: $country)\n availableToDate\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n fallBackClips: content(country: \"US\", language: \"en\") {\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n backdrops {\n backdropUrl\n __typename\n }\n fullBackdrops: backdrops(profile: S1920, format: JPG) {\n backdropUrl\n __typename\n }\n clips {\n ...TrailerClips\n __typename\n }\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n externalIds {\n imdbId\n __typename\n }\n fullPath\n genres {\n shortName\n __typename\n }\n posterUrl\n fullPosterUrl: posterUrl(profile: S718, format: JPG)\n runtime\n isReleased\n scoring {\n imdbScore\n imdbVotes\n tmdbPopularity\n tmdbScore\n jwRating\n __typename\n }\n shortDescription\n title\n originalReleaseYear\n originalReleaseDate\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseCountDown(country: $country)\n releaseDate\n label\n package {\n id\n packageId\n shortName\n clearName\n __typename\n }\n __typename\n }\n ... on MovieOrShowContent {\n originalTitle\n ageCertification\n credits {\n role\n name\n characterName\n personId\n __typename\n }\n interactions {\n dislikelistAdditions\n likelistAdditions\n votesNumber\n __typename\n }\n productionCountries\n __typename\n }\n ... on SeasonContent {\n seasonNumber\n interactions {\n dislikelistAdditions\n likelistAdditions\n votesNumber\n __typename\n }\n __typename\n }\n __typename\n }\n popularityRank(country: $country) {\n rank\n trend\n trendDifference\n __typename\n }\n __typename\n }\n ... on MovieOrShow {\n watchlistEntryV2 {\n createdAt\n __typename\n }\n likelistEntry {\n createdAt\n __typename\n }\n dislikelistEntry {\n createdAt\n __typename\n }\n customlistEntries {\n createdAt\n genericTitleList {\n id\n __typename\n }\n __typename\n }\n similarTitlesV2(\n country: $country\n allowSponsoredRecommendations: $allowSponsoredRecommendations\n ) {\n sponsoredAd {\n ...SponsoredAdTitleDetail\n __typename\n }\n __typename\n }\n __typename\n }\n ... on Movie {\n permanentAudiences\n seenlistEntry {\n createdAt\n __typename\n }\n __typename\n }\n ... on Show {\n permanentAudiences\n totalSeasonCount\n seenState(country: $country) {\n progress\n seenEpisodeCount\n __typename\n }\n tvShowTrackingEntry {\n createdAt\n __typename\n }\n seasons(sortDirection: DESC) {\n id\n objectId\n objectType\n totalEpisodeCount\n availableTo(country: $country, platform: $platform) {\n availableToDate\n availableCountDown(country: $country)\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n posterUrl\n seasonNumber\n fullPath\n title\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n releaseCountDown(country: $country)\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n isReleased\n originalReleaseYear\n __typename\n }\n show {\n id\n objectId\n objectType\n watchlistEntryV2 {\n createdAt\n __typename\n }\n content(country: $country, language: $language) {\n title\n __typename\n }\n __typename\n }\n __typename\n }\n recentEpisodes: episodes(\n sortDirection: DESC\n limit: 3\n releasedInCountry: $country\n ) {\n id\n objectId\n content(country: $country, language: $language) {\n title\n shortDescription\n episodeNumber\n seasonNumber\n isReleased\n upcomingReleases {\n releaseDate\n label\n __typename\n }\n __typename\n }\n seenlistEntry {\n createdAt\n __typename\n }\n __typename\n }\n __typename\n }\n ... on Season {\n totalEpisodeCount\n episodes(limit: $episodeMaxLimit) {\n id\n objectType\n objectId\n seenlistEntry {\n createdAt\n __typename\n }\n content(country: $country, language: $language) {\n title\n shortDescription\n episodeNumber\n seasonNumber\n isReleased\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n label\n package {\n id\n packageId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n show {\n id\n objectId\n objectType\n totalSeasonCount\n customlistEntries {\n createdAt\n genericTitleList {\n id\n __typename\n }\n __typename\n }\n tvShowTrackingEntry {\n createdAt\n __typename\n }\n fallBackClips: content(country: \"US\", language: \"en\") {\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n title\n ageCertification\n fullPath\n genres {\n shortName\n __typename\n }\n credits {\n role\n name\n characterName\n personId\n __typename\n }\n productionCountries\n externalIds {\n imdbId\n __typename\n }\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n __typename\n }\n backdrops {\n backdropUrl\n __typename\n }\n posterUrl\n isReleased\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n seenState(country: $country) {\n progress\n __typename\n }\n watchlistEntryV2 {\n createdAt\n __typename\n }\n dislikelistEntry {\n createdAt\n __typename\n }\n likelistEntry {\n createdAt\n __typename\n }\n similarTitlesV2(\n country: $country\n allowSponsoredRecommendations: $allowSponsoredRecommendations\n ) {\n sponsoredAd {\n ...SponsoredAdTitleDetail\n __typename\n }\n __typename\n }\n __typename\n }\n seenState(country: $country) {\n progress\n __typename\n }\n __typename\n }\n }\n __typename\n }\n}\n\nfragment TrailerClips on Clip {\n sourceUrl\n externalId\n provider\n name\n __typename\n}\n\nfragment SponsoredAdTitleDetail on SponsoredRecommendationAd {\n bidId\n holdoutGroup\n campaign {\n externalTrackers {\n type\n data\n __typename\n }\n hideRatings\n promotionalImageUrl\n promotionalVideo {\n url\n __typename\n }\n promotionalText\n watchNowLabel\n watchNowOffer {\n standardWebURL\n presentationType\n monetizationType\n package {\n id\n packageId\n shortName\n clearName\n icon\n __typename\n }\n __typename\n }\n node {\n nodeId: id\n ... on MovieOrShow {\n content(country: $country, language: $language) {\n fullPath\n posterUrl\n title\n originalReleaseYear\n scoring {\n imdbScore\n __typename\n }\n externalIds {\n imdbId\n __typename\n }\n backdrops(format: $format, profile: $backdropProfile) {\n backdropUrl\n __typename\n }\n isReleased\n __typename\n }\n objectId\n objectType\n offers(country: $country, platform: $platform) {\n monetizationType\n presentationType\n package {\n id\n packageId\n __typename\n }\n id\n __typename\n }\n watchlistEntryV2 {\n createdAt\n __typename\n }\n __typename\n }\n ... on Show {\n seenState(country: $country) {\n seenEpisodeCount\n __typename\n }\n __typename\n }\n ... on GenericTitleList {\n followedlistEntry {\n createdAt\n name\n __typename\n }\n id\n name\n type\n visibility\n titles(country: $country) {\n totalCount\n edges {\n cursor\n node {\n content(country: $country, language: $language) {\n fullPath\n posterUrl\n title\n originalReleaseYear\n scoring {\n imdbScore\n __typename\n }\n isReleased\n __typename\n }\n id\n objectId\n objectType\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n}\n" + }), + credentials : "include" + } + ) + .then(response => response.json()) + .then(response => { + this.seasons = {}; + if (response.data.urlV2.node.seasons && response.data.urlV2.node.seasons.length > 0) { + this.seasons = response.data.urlV2.node.seasons.map((item) => { + var poster = null; + if (item.content.posterUrl) { + poster = item.content.posterUrl.replace('{profile}', 's276'); + } + return { + id: item.id, + title: item.content.title, + type: item.objectType, + poster_url: `https://images.justwatch.com${poster}`, + fullPath: item.content.fullPath, + }; + }); + this.step += 1; + } else { + this.step += 1; + this.loadItem(index, false); + } + }); }, loadItem(index, isSeason) { this.offers = {}; @@ -341,22 +392,46 @@ var app = new Vue({ if (isSeason) { searchItem = this.seasons[index]; } - var url = `${JUSTWATCH_API_DOMAIN}/content/titles/${searchItem.type}/${searchItem.id}/locale/${locale}?language=fr` - promises.push(fetch(url, { credentials : "include" }) + promises.push(fetch( + `${JUSTWATCH_API_DOMAIN}/graphql`, + { + method: 'POST', + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + "operationName": "GetUrlTitleDetails", + "variables": { + "platform": "WEB", + "fullPath": searchItem.fullPath, + "language": "fr", + "country": locale, + "episodeMaxLimit": 20, + "allowSponsoredRecommendations": { + "appId": "3.8.2-webapp#dec565e", + "country": "FR", + "language": "fr", + "pageType": "VIEW_TITLE_DETAIL", + "placement": "DETAIL_PAGE", + "platform": "WEB", + "supportedObjectTypes": ["MOVIE", "SHOW", "GENERIC_TITLE_LIST"], + "supportedFormats": ["IMAGE", "VIDEO"] + } + }, + "query": "query GetUrlTitleDetails($fullPath: String!, $country: Country!, $language: Language!, $episodeMaxLimit: Int, $platform: Platform! = WEB, $allowSponsoredRecommendations: SponsoredRecommendationsInput, $format: ImageFormat, $backdropProfile: BackdropProfile) {\n urlV2(fullPath: $fullPath) {\n id\n metaDescription\n metaKeywords\n metaRobots\n metaTitle\n heading1\n heading2\n htmlContent\n node {\n id\n __typename\n ... on MovieOrShowOrSeason {\n plexPlayerOffers: offers(\n country: $country\n platform: $platform\n filter: {packages: [\"pxp\"]}\n ) {\n id\n standardWebURL\n package {\n id\n packageId\n clearName\n technicalName\n shortName\n __typename\n }\n __typename\n }\n disneyOffersCount: offerCount(\n country: $country\n platform: $platform\n filter: {packages: [\"dnp\"]}\n )\n objectType\n objectId\n offerCount(country: $country, platform: $platform)\n offers(country: $country, platform: $platform) {\n monetizationType\n elementCount\n package {\n id\n packageId\n clearName\n __typename\n }\n __typename\n }\n watchNowOffer(country: $country, platform: $platform) {\n id\n standardWebURL\n __typename\n }\n promotedBundles(country: $country, platform: $platform) {\n promotionUrl\n __typename\n }\n availableTo(country: $country, platform: $platform) {\n availableCountDown(country: $country)\n availableToDate\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n fallBackClips: content(country: \"US\", language: \"en\") {\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n backdrops {\n backdropUrl\n __typename\n }\n fullBackdrops: backdrops(profile: S1920, format: JPG) {\n backdropUrl\n __typename\n }\n clips {\n ...TrailerClips\n __typename\n }\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n externalIds {\n imdbId\n __typename\n }\n fullPath\n genres {\n shortName\n __typename\n }\n posterUrl\n fullPosterUrl: posterUrl(profile: S718, format: JPG)\n runtime\n isReleased\n scoring {\n imdbScore\n imdbVotes\n tmdbPopularity\n tmdbScore\n jwRating\n __typename\n }\n shortDescription\n title\n originalReleaseYear\n originalReleaseDate\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseCountDown(country: $country)\n releaseDate\n label\n package {\n id\n packageId\n shortName\n clearName\n __typename\n }\n __typename\n }\n ... on MovieOrShowContent {\n originalTitle\n ageCertification\n credits {\n role\n name\n characterName\n personId\n __typename\n }\n interactions {\n dislikelistAdditions\n likelistAdditions\n votesNumber\n __typename\n }\n productionCountries\n __typename\n }\n ... on SeasonContent {\n seasonNumber\n interactions {\n dislikelistAdditions\n likelistAdditions\n votesNumber\n __typename\n }\n __typename\n }\n __typename\n }\n popularityRank(country: $country) {\n rank\n trend\n trendDifference\n __typename\n }\n __typename\n }\n ... on MovieOrShow {\n watchlistEntryV2 {\n createdAt\n __typename\n }\n likelistEntry {\n createdAt\n __typename\n }\n dislikelistEntry {\n createdAt\n __typename\n }\n customlistEntries {\n createdAt\n genericTitleList {\n id\n __typename\n }\n __typename\n }\n similarTitlesV2(\n country: $country\n allowSponsoredRecommendations: $allowSponsoredRecommendations\n ) {\n sponsoredAd {\n ...SponsoredAdTitleDetail\n __typename\n }\n __typename\n }\n __typename\n }\n ... on Movie {\n permanentAudiences\n seenlistEntry {\n createdAt\n __typename\n }\n __typename\n }\n ... on Show {\n permanentAudiences\n totalSeasonCount\n seenState(country: $country) {\n progress\n seenEpisodeCount\n __typename\n }\n tvShowTrackingEntry {\n createdAt\n __typename\n }\n seasons(sortDirection: DESC) {\n id\n objectId\n objectType\n totalEpisodeCount\n availableTo(country: $country, platform: $platform) {\n availableToDate\n availableCountDown(country: $country)\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n posterUrl\n seasonNumber\n fullPath\n title\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n releaseCountDown(country: $country)\n package {\n id\n shortName\n __typename\n }\n __typename\n }\n isReleased\n originalReleaseYear\n __typename\n }\n show {\n id\n objectId\n objectType\n watchlistEntryV2 {\n createdAt\n __typename\n }\n content(country: $country, language: $language) {\n title\n __typename\n }\n __typename\n }\n __typename\n }\n recentEpisodes: episodes(\n sortDirection: DESC\n limit: 3\n releasedInCountry: $country\n ) {\n id\n objectId\n content(country: $country, language: $language) {\n title\n shortDescription\n episodeNumber\n seasonNumber\n isReleased\n upcomingReleases {\n releaseDate\n label\n __typename\n }\n __typename\n }\n seenlistEntry {\n createdAt\n __typename\n }\n __typename\n }\n __typename\n }\n ... on Season {\n totalEpisodeCount\n episodes(limit: $episodeMaxLimit) {\n id\n objectType\n objectId\n seenlistEntry {\n createdAt\n __typename\n }\n content(country: $country, language: $language) {\n title\n shortDescription\n episodeNumber\n seasonNumber\n isReleased\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n label\n package {\n id\n packageId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n show {\n id\n objectId\n objectType\n totalSeasonCount\n customlistEntries {\n createdAt\n genericTitleList {\n id\n __typename\n }\n __typename\n }\n tvShowTrackingEntry {\n createdAt\n __typename\n }\n fallBackClips: content(country: \"US\", language: \"en\") {\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n content(country: $country, language: $language) {\n title\n ageCertification\n fullPath\n genres {\n shortName\n __typename\n }\n credits {\n role\n name\n characterName\n personId\n __typename\n }\n productionCountries\n externalIds {\n imdbId\n __typename\n }\n upcomingReleases(releaseTypes: DIGITAL) {\n releaseDate\n __typename\n }\n backdrops {\n backdropUrl\n __typename\n }\n posterUrl\n isReleased\n videobusterClips: clips(providers: [VIDEOBUSTER]) {\n ...TrailerClips\n __typename\n }\n dailymotionClips: clips(providers: [DAILYMOTION]) {\n ...TrailerClips\n __typename\n }\n __typename\n }\n seenState(country: $country) {\n progress\n __typename\n }\n watchlistEntryV2 {\n createdAt\n __typename\n }\n dislikelistEntry {\n createdAt\n __typename\n }\n likelistEntry {\n createdAt\n __typename\n }\n similarTitlesV2(\n country: $country\n allowSponsoredRecommendations: $allowSponsoredRecommendations\n ) {\n sponsoredAd {\n ...SponsoredAdTitleDetail\n __typename\n }\n __typename\n }\n __typename\n }\n seenState(country: $country) {\n progress\n __typename\n }\n __typename\n }\n }\n __typename\n }\n}\n\nfragment TrailerClips on Clip {\n sourceUrl\n externalId\n provider\n name\n __typename\n}\n\nfragment SponsoredAdTitleDetail on SponsoredRecommendationAd {\n bidId\n holdoutGroup\n campaign {\n externalTrackers {\n type\n data\n __typename\n }\n hideRatings\n promotionalImageUrl\n promotionalVideo {\n url\n __typename\n }\n promotionalText\n watchNowLabel\n watchNowOffer {\n standardWebURL\n presentationType\n monetizationType\n package {\n id\n packageId\n shortName\n clearName\n icon\n __typename\n }\n __typename\n }\n node {\n nodeId: id\n ... on MovieOrShow {\n content(country: $country, language: $language) {\n fullPath\n posterUrl\n title\n originalReleaseYear\n scoring {\n imdbScore\n __typename\n }\n externalIds {\n imdbId\n __typename\n }\n backdrops(format: $format, profile: $backdropProfile) {\n backdropUrl\n __typename\n }\n isReleased\n __typename\n }\n objectId\n objectType\n offers(country: $country, platform: $platform) {\n monetizationType\n presentationType\n package {\n id\n packageId\n __typename\n }\n id\n __typename\n }\n watchlistEntryV2 {\n createdAt\n __typename\n }\n __typename\n }\n ... on Show {\n seenState(country: $country) {\n seenEpisodeCount\n __typename\n }\n __typename\n }\n ... on GenericTitleList {\n followedlistEntry {\n createdAt\n name\n __typename\n }\n id\n name\n type\n visibility\n titles(country: $country) {\n totalCount\n edges {\n cursor\n node {\n content(country: $country, language: $language) {\n fullPath\n posterUrl\n title\n originalReleaseYear\n scoring {\n imdbScore\n __typename\n }\n isReleased\n __typename\n }\n id\n objectId\n objectType\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n}\n" + }), + credentials : "include" + } + ) .then(response => response.json()) .then(response => { - if (!response.offers) { + if (!response.data.urlV2.node.offers) { this.offers[locale] = []; return; } - this.offers[locale] = response.offers - .filter(item => item.monetization_type == 'flatrate' || item.monetization_type == 'ads') - .map(item => { - return { - url: item.urls.standard_web, - type: item.presentation_type, - } - }); + this.offers[locale] = response.data.urlV2.node.offers + .filter(item => item.monetizationType == 'FLATRATE' || item.monetizationType == 'ADS') + .map(item => item.package.clearName); this.offers[locale] = [...new Set(this.offers[locale])]; }) .catch(exc => this.error = exc)