mirror of
https://github.com/movixcorp/MovixOpenSource.git
synced 2026-07-27 09:12:07 +00:00
698 lines
115 KiB
Python
698 lines
115 KiB
Python
import builtins
|
|
import json
|
|
import re
|
|
from os.path import join
|
|
from urllib.parse import urlparse, parse_qs, quote
|
|
|
|
import browser_cookie3
|
|
import requests
|
|
import xmltodict
|
|
|
|
import utils.tools.cdm as cdm_tools
|
|
from utils.constants.macros import ERR_MSG, USER_ERROR, APP_ERROR
|
|
from utils.main_service import main_service
|
|
from utils.structs import BaseElement, BaseService, CustomException
|
|
from utils.tools.args import check_range
|
|
from utils.tools.common import get_valid_filename, clean_url
|
|
|
|
|
|
class vrt_be(BaseService):
|
|
DEMO_URLS = [
|
|
"https://www.vrt.be/vrtmax/a-z/knokke-off/#afleveringen",
|
|
"https://www.vrt.be/vrtmax/a-z/doc-martin/#afleveringen",
|
|
"https://www.vrt.be/vrtmax/a-z/dag---nacht/#trailer",
|
|
"https://www.vrt.be/vrtmax/a-z/thuis/#alle-seizoenen",
|
|
"https://www.vrt.be/vrtmax/a-z/thuis/#throwbackthuis",
|
|
"https://www.vrt.be/vrtmax/a-z/fc-de-kampioenen/?seizoen=extras#afleveringen",
|
|
"https://www.vrt.be/vrtmax/a-z/postbus-x/",
|
|
"https://www.vrt.be/vrtmax/podcasts/studio-brussel/d/de-popcast-van-de-week/#afleveringen",
|
|
"https://www.vrt.be/vrtmax/luister/radio/m/mnm50~55-17/#uitzendingen",
|
|
"https://www.vrt.be/vrtmax/luister/radio/i/iedereen-klassiek~31-16/iedereen-klassiek~31-23781-0/",
|
|
"https://www.vrt.be/vrtmax/livestream/audio/klara/",
|
|
"https://www.vrt.be/vrtmax/livestream/video/ketnet/"
|
|
"https://www.vrt.be/vrtmax/livestream/video/vrt-canvas/",
|
|
"https://www.vrt.be/vrtmax/podcasts/mnm/0/22-minuten-stomme-vragen-/3/gustaph/",
|
|
"https://www.vrt.be/vrtmax/a-z/de-gruffalo/2009/de-gruffalo/",
|
|
]
|
|
|
|
TOKENS_URL = 'https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/external/v2/tokens'
|
|
ITEMS_URL = 'https://media-services-public.vrt.be/media-aggregator/v2/media-items/{id}'
|
|
GRAPHQL_URL = 'https://www.vrt.be/vrtnu-api/graphql/public/v1'
|
|
REFRESH_URL = 'https://www.vrt.be/vrtmax/sso/refresh'
|
|
BASE_URL = 'https://www.vrt.be'
|
|
LICENSE_URL = 'https://widevine-proxy.drm.technology/proxy'
|
|
|
|
PLAYER_TOKEN = None
|
|
PAGE_SIZE = 90
|
|
|
|
@staticmethod
|
|
def test_service():
|
|
main_service.run_service(vrt_be)
|
|
|
|
@staticmethod
|
|
def is_content_livestream(content, additional):
|
|
return "/livestream/audio/" in content or "/livestream/video/" in content
|
|
|
|
@staticmethod
|
|
def credentials_needed():
|
|
return {
|
|
"OPTIONAL": True,
|
|
"FIREFOX_COOKIES": True
|
|
}
|
|
|
|
@staticmethod
|
|
def get_player_token():
|
|
vrt_be_cookies = {}
|
|
try:
|
|
for c in browser_cookie3.firefox(domain_name='vrt.be'):
|
|
vrt_be_cookies[c.name] = c.value
|
|
except browser_cookie3.BrowserCookieError:
|
|
pass
|
|
|
|
response = json.loads(requests.get(
|
|
vrt_be.REFRESH_URL, cookies=vrt_be_cookies
|
|
).content.decode())
|
|
vrt_be_cookies["vrtnu-site_profile_vt"] = response.get("tokens", {}).get("video_token", "")
|
|
|
|
player_token = json.loads(requests.post(
|
|
vrt_be.TOKENS_URL,
|
|
json={'identityToken': vrt_be_cookies.get("vrtnu-site_profile_vt", "")}
|
|
).content.decode())["vrtPlayerToken"]
|
|
return player_token
|
|
|
|
@staticmethod
|
|
def initialize_service():
|
|
if vrt_be.PLAYER_TOKEN is None:
|
|
vrt_be.PLAYER_TOKEN = vrt_be.get_player_token()
|
|
if vrt_be.PLAYER_TOKEN is None:
|
|
return None
|
|
return vrt_be
|
|
|
|
@staticmethod
|
|
def get_keys(challenge, additional):
|
|
licence = requests.post(
|
|
vrt_be.LICENSE_URL,
|
|
data=json.dumps({
|
|
"token": additional["token"],
|
|
"drm_info": list(challenge)
|
|
})
|
|
)
|
|
licence.raise_for_status()
|
|
return licence.content
|
|
|
|
@staticmethod
|
|
def get_init_from_mpd(mpd_url):
|
|
mpd_content = requests.get(mpd_url).content.decode()
|
|
mpd_content = xmltodict.parse(mpd_content)["MPD"]["Period"]
|
|
base_url = mpd_content["BaseURL"]
|
|
if type(mpd_content["AdaptationSet"]) is not list:
|
|
mpd_content["AdaptationSet"] = [mpd_content["AdaptationSet"]]
|
|
|
|
best_content = None
|
|
best_height = None
|
|
best_bandwidth = None
|
|
for content in mpd_content["AdaptationSet"]:
|
|
if content["@contentType"] != "video":
|
|
continue
|
|
update_content = False
|
|
|
|
height = content.get("@maxHeight", content.get("@height", None))
|
|
if height is None:
|
|
continue
|
|
height = int(height)
|
|
bandwidth = content.get("@maxBandwidth", content.get("@bandwidth", None))
|
|
|
|
if best_content is None:
|
|
update_content = True
|
|
else:
|
|
if height > best_height:
|
|
update_content = True
|
|
elif height == best_height:
|
|
if bandwidth is not None:
|
|
if best_bandwidth is None:
|
|
update_content = True
|
|
elif int(bandwidth) > int(best_bandwidth):
|
|
update_content = True
|
|
|
|
if update_content:
|
|
best_content = content
|
|
best_height = height
|
|
best_bandwidth = bandwidth
|
|
|
|
mpd_content = best_content
|
|
init_url = mpd_content["SegmentTemplate"]["@initialization"]
|
|
if type(mpd_content["Representation"]) is not list:
|
|
mpd_content["Representation"] = [mpd_content["Representation"]]
|
|
|
|
best_content = None
|
|
for content in mpd_content["Representation"]:
|
|
if best_content is None:
|
|
best_content = content
|
|
continue
|
|
if int(content["@height"]) > int(best_content["@height"]):
|
|
best_content = content
|
|
continue
|
|
elif int(content["@height"]) == int(best_content["@height"]):
|
|
if int(content["@bandwidth"]) > int(best_content["@bandwidth"]):
|
|
best_content = content
|
|
continue
|
|
|
|
init_url = init_url.replace("$RepresentationID$", best_content["@id"])
|
|
init_url = '/'.join(mpd_url.split('/')[:-1]) + "/" + base_url + init_url
|
|
return init_url
|
|
|
|
@staticmethod
|
|
def get_pssh_from_manifest(manifest):
|
|
return cdm_tools.get_pssh_from_init(vrt_be.get_init_from_mpd(manifest))
|
|
|
|
@staticmethod
|
|
def get_stream_data(url):
|
|
response = {}
|
|
action_type = None
|
|
|
|
if "/a-z/" in url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query VideoPage($pageId: ID!) {\n page(id: $pageId) {\n ... on EpisodePage {\n objectId\n title\n brand\n permalink\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n ...trackingDataFragment\n __typename\n }\n ldjson\n player {\n ...playerFragment\n __typename\n }\n episode {\n objectId\n title\n available\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n logo\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n playlist {\n __typename\n objectId\n activeListId\n lists {\n ... on StaticTileList {\n ...basicStaticTileListFragment\n __typename\n }\n __typename\n }\n }\n durationSeconds\n announcementValue\n name\n subtitle\n richDescription {\n __typename\n html\n }\n program {\n objectId\n link\n title\n __typename\n }\n watchAction {\n streamId\n videoId\n avodUrl\n resumePoint\n completed\n __typename\n }\n shareAction {\n title\n description\n image {\n templateUrl\n __typename\n }\n url\n __typename\n }\n favoriteAction {\n id\n title\n favorite\n programWhatsonId\n programUrl\n __typename\n }\n __typename\n }\n menu {\n ...menuFragment\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}\nfragment playerFragment on MediaPlayer {\n __typename\n objectId\n expires\n image {\n ...imageFragment\n __typename\n }\n listenAction {\n __typename\n ... on LiveListenAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on PodcastEpisodeListenAction {\n streamId\n pageLink: podcastEpisodeLink\n resumePointId: audioId\n resumePoint\n completed\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n radioEpisodeId\n pageLink\n startDate\n endDate\n __typename\n }\n }\n modes {\n __typename\n active\n token {\n placeholder\n value\n __typename\n }\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n sportBuffStreamId\n subtitle\n title\n watchAction {\n __typename\n ... on LiveWatchAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on EpisodeWatchAction {\n streamId\n pageLink: videoUrl\n resumePointId: videoId\n resumePoint\n completed\n avodUrl\n __typename\n }\n }\n}\nfragment menuFragment on ContainerNavigation {\n __typename\n objectId\n items {\n __typename\n objectId\n componentId\n title\n active\n }\n}\nfragment basicStaticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n displayType\n expires\n tileVariant\n tileContentType\n tileOrientation\n title\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}',
|
|
'operationName': 'VideoPage',
|
|
'variables': {'pageId': f'/vrtnu/{url.split("/vrtmax/")[1]}.model.json'}
|
|
}
|
|
).content.decode())
|
|
action_type = "watchAction"
|
|
|
|
if "/podcasts/" in url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query PodcastPage($pageId: ID!) {\n page(id: $pageId) {\n ... on PodcastEpisodePage {\n objectId\n permalink\n brand\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n ldjson\n components {\n __typename\n ... on IComponent {\n ... on PageHeader {\n objectId\n categories {\n title\n name\n category\n __typename\n }\n brandsLogos {\n brand\n brandTitle\n logos {\n mono\n primary\n type\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n ... on ContainerNavigation {\n objectId\n __typename\n }\n }\n menu {\n ...menuFragment\n __typename\n }\n player {\n ...playerFragment\n __typename\n }\n podcastEpisode {\n objectId\n title\n available\n richDescription {\n __typename\n html\n }\n image {\n objectId\n templateUrl\n __typename\n }\n listenAction {\n audioId\n streamId\n publicationDate\n resumePoint\n completed\n __typename\n }\n presenters {\n name\n category\n title\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n shareAction {\n title\n description\n image {\n objectId\n templateUrl\n __typename\n }\n url\n __typename\n }\n podcastProgram {\n objectId\n title\n link\n __typename\n }\n podcastSeason {\n objectId\n title\n __typename\n }\n episodeNumberRaw\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment menuFragment on ContainerNavigation {\n __typename\n objectId\n items {\n __typename\n objectId\n componentId\n title\n active\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment playerFragment on MediaPlayer {\n __typename\n objectId\n expires\n image {\n ...imageFragment\n __typename\n }\n listenAction {\n __typename\n ... on LiveListenAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on PodcastEpisodeListenAction {\n streamId\n pageLink: podcastEpisodeLink\n resumePointId: audioId\n resumePoint\n completed\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n radioEpisodeId\n pageLink\n startDate\n endDate\n __typename\n }\n }\n modes {\n __typename\n active\n token {\n placeholder\n value\n __typename\n }\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n sportBuffStreamId\n subtitle\n title\n watchAction {\n __typename\n ... on LiveWatchAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on EpisodeWatchAction {\n streamId\n pageLink: videoUrl\n resumePointId: videoId\n resumePoint\n completed\n avodUrl\n __typename\n }\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}',
|
|
'operationName': 'PodcastPage',
|
|
'variables': {'pageId': f'/vrtnu/{url.split("/vrtmax/")[1]}.model.json'}
|
|
}
|
|
).content.decode())
|
|
action_type = "listenAction"
|
|
|
|
if "/livestream/audio/" in url or "/livestream/video/" in url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query Livestream($pageId: ID!, $miniQuery: Boolean = false) {\n page(id: $pageId) {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IPage @skip(if: $miniQuery) {\n title\n brand\n permalink\n trackingData {\n ...trackingDataFragment\n __typename\n }\n components {\n __typename\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ...bannerFragment\n }\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n __typename\n }\n ... on AudioLivestreamPage {\n linkTemplate\n description\n livestream {\n objectId\n title\n presenters {\n name\n title\n category\n __typename\n }\n ... on AudioLivestream @skip(if: $miniQuery) {\n actionItems {\n ...actionItemFragment\n __typename\n }\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n shareAction {\n title\n url\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n __typename\n }\n __typename\n }\n player {\n ...playerFragment\n __typename\n }\n menu @skip(if: $miniQuery) {\n ...menuFragment\n __typename\n }\n __typename\n }\n ... on LivestreamPage {\n description\n livestream {\n objectId\n brandLogos @skip(if: $miniQuery) {\n ...brandLogosFragment\n __typename\n }\n shareAction @skip(if: $miniQuery) {\n title\n url\n __typename\n }\n title\n primaryMeta @skip(if: $miniQuery) {\n ...metaFragment\n __typename\n }\n episode @skip(if: $miniQuery) {\n ... on Episode {\n objectId\n program {\n ... on Program {\n objectId\n title\n description\n link\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n player {\n ...playerFragment\n __typename\n }\n menu {\n ...menuFragment\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment bannerFragment on Banner {\n __typename\n objectId\n brand\n countdown {\n date\n __typename\n }\n richDescription {\n __typename\n text\n }\n ctaText\n image {\n objectId\n templateUrl\n alt\n focalPoint\n __typename\n }\n title\n compactLayout\n textTheme\n backgroundColor\n style\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n titleArt {\n objectId\n templateUrl\n __typename\n }\n labelMeta {\n __typename\n type\n value\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment playerFragment on MediaPlayer {\n __typename\n objectId\n expires\n image {\n ...imageFragment\n __typename\n }\n listenAction {\n __typename\n ... on LiveListenAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on PodcastEpisodeListenAction {\n streamId\n pageLink: podcastEpisodeLink\n resumePointId: audioId\n resumePoint\n completed\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n radioEpisodeId\n pageLink\n startDate\n endDate\n __typename\n }\n }\n modes {\n __typename\n active\n token {\n placeholder\n value\n __typename\n }\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n sportBuffStreamId\n subtitle\n title\n watchAction {\n __typename\n ... on LiveWatchAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on EpisodeWatchAction {\n streamId\n pageLink: videoUrl\n resumePointId: videoId\n resumePoint\n completed\n avodUrl\n __typename\n }\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}\nfragment menuFragment on ContainerNavigation {\n __typename\n objectId\n items {\n __typename\n objectId\n componentId\n title\n active\n }\n}',
|
|
'operationName': 'Livestream',
|
|
'variables': {'pageId': f'/vrtmax/{url.split("/vrtmax/")[1]}/'}
|
|
}
|
|
).content.decode())
|
|
if "/livestream/audio/" in url:
|
|
action_type = "listenAction"
|
|
else:
|
|
action_type = "watchAction"
|
|
|
|
if "/luister/radio/" in url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query RadioEpisodePage($pageId: ID!) {\n page(id: $pageId) {\n ... on RadioEpisodePage {\n objectId\n title\n brand\n permalink\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n ...trackingDataFragment\n __typename\n }\n header {\n title\n announcementValue\n brandsLogos {\n brandTitle\n logos {\n type\n mono\n width\n height\n __typename\n }\n __typename\n }\n __typename\n }\n menu {\n ...menuFragment\n __typename\n }\n player {\n ...playerFragment\n __typename\n }\n radioEpisode {\n objectId\n title\n richDescription {\n __typename\n html\n text\n }\n brand\n startDate\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n brand\n presenters {\n name\n category\n title\n icon\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment playerFragment on MediaPlayer {\n __typename\n objectId\n expires\n image {\n ...imageFragment\n __typename\n }\n listenAction {\n __typename\n ... on LiveListenAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on PodcastEpisodeListenAction {\n streamId\n pageLink: podcastEpisodeLink\n resumePointId: audioId\n resumePoint\n completed\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n radioEpisodeId\n pageLink\n startDate\n endDate\n __typename\n }\n }\n modes {\n __typename\n active\n token {\n placeholder\n value\n __typename\n }\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n sportBuffStreamId\n subtitle\n title\n watchAction {\n __typename\n ... on LiveWatchAction {\n streamId\n pageLink: livestreamPageLink\n startDate\n __typename\n }\n ... on EpisodeWatchAction {\n streamId\n pageLink: videoUrl\n resumePointId: videoId\n resumePoint\n completed\n avodUrl\n __typename\n }\n }\n}\nfragment menuFragment on ContainerNavigation {\n __typename\n objectId\n items {\n __typename\n objectId\n componentId\n title\n active\n }\n}',
|
|
'operationName': 'RadioEpisodePage',
|
|
'variables': {'pageId': f'/vrtnu/{url.split("/vrtmax/")[1]}/'}
|
|
}
|
|
).content.decode())
|
|
action_type = "listenAction"
|
|
|
|
if action_type is None:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=f'{USER_ERROR}',
|
|
url=url,
|
|
reason="URL not supported",
|
|
solution=f"Extend the {vrt_be.__name__} service"
|
|
))
|
|
|
|
response = response["data"]["page"]
|
|
if response is None or response["player"][action_type] is None:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=f'{USER_ERROR}',
|
|
url=url,
|
|
reason="The content isn't available",
|
|
solution="Do not attempt to download it"
|
|
))
|
|
|
|
response = response["player"]
|
|
return response[action_type]["streamId"], response["title"]
|
|
|
|
@staticmethod
|
|
def get_video_data(source_element):
|
|
source_element.url = source_element.url.rstrip('/')
|
|
stream_id, stream_title = vrt_be.get_stream_data(source_element.url)
|
|
|
|
response = requests.get(
|
|
vrt_be.ITEMS_URL.format(id=stream_id),
|
|
params={
|
|
'vrtPlayerToken': vrt_be.PLAYER_TOKEN,
|
|
'client': 'vrtnu-web@PROD'
|
|
}
|
|
)
|
|
|
|
if response.status_code == 404:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=f'{USER_ERROR}',
|
|
url=source_element.url,
|
|
reason="The content isn't available",
|
|
solution="Do not attempt to download it"
|
|
))
|
|
|
|
response = json.loads(response.content.decode())
|
|
message = response.get("code", "").lower()
|
|
if "available_only" in message:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=f'{USER_ERROR}',
|
|
url=source_element.url,
|
|
reason="Need Belgian IP to access content",
|
|
solution="Use a VPN"
|
|
))
|
|
if "authentication" in message or "restricted" in message:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=USER_ERROR,
|
|
url=source_element.url,
|
|
reason='Need account for this content and/or fresh cookies',
|
|
solution=f'Sign into your account using Firefox and play a random video. '
|
|
f'If it persists then debug the {vrt_be.__name__} service'
|
|
))
|
|
|
|
if len(message) > 0:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=APP_ERROR,
|
|
url=source_element.url,
|
|
reason=f"Unknown error encountered: {str(response)}",
|
|
solution=f"Debug the {vrt_be.__name__} service"
|
|
))
|
|
|
|
if source_element.element is None:
|
|
if response["title"] is None or len(response["title"].strip()) == 0:
|
|
response["title"] = stream_title
|
|
source_element.element = get_valid_filename(response["title"])
|
|
if source_element.collection is None:
|
|
source_element.collection = join(
|
|
str(builtins.CONFIG["DOWNLOAD_COMMANDS"]["OUTPUT_MEDIA_PATH"]),
|
|
vrt_be.__name__
|
|
)
|
|
|
|
manifest = None
|
|
for target in response['targetUrls']:
|
|
if "dash" in target["type"].lower():
|
|
manifest = target["url"]
|
|
break
|
|
|
|
pssh_value = None
|
|
if response["drm"] is not None:
|
|
pssh_value = vrt_be.get_pssh_from_manifest(manifest)
|
|
return manifest, pssh_value, {"token": response["drm"]}
|
|
|
|
@staticmethod
|
|
def get_label_index(label):
|
|
if label is None or len(label) == 0:
|
|
return None
|
|
label = label.lower()
|
|
label = re.sub(r'\s+', ' ', label)
|
|
label = label.replace(' ', "_")
|
|
for s in [
|
|
"seizoen_", "aflevering_", "afl\\.", "-s\\d+a", "-s\\d+-a", "-\\d+a", "-\\d+-a",
|
|
"-s\\d+a-", "-s\\d+-a-", "-\\d+a-", "-\\d+-a-", "sspecialsa"
|
|
]:
|
|
try:
|
|
return int(re.findall(fr'{s}(\d+)', label)[0])
|
|
except:
|
|
pass
|
|
return None
|
|
|
|
@staticmethod
|
|
def get_episode_index(metadata, url):
|
|
for meta in metadata:
|
|
value = meta["value"].lower()
|
|
if "aflevering" in value or "afl" in value:
|
|
return vrt_be.get_label_index(meta["value"])
|
|
|
|
index = vrt_be.get_label_index(url)
|
|
if index is None:
|
|
raise CustomException(ERR_MSG.format(
|
|
type=APP_ERROR,
|
|
url=url,
|
|
reason="Failed to extract the episode index",
|
|
solution=f"Debug the {vrt_be.__name__} service"
|
|
))
|
|
return index
|
|
|
|
@staticmethod
|
|
def check_order(type_elements, elements):
|
|
if len(elements) < 2:
|
|
return True
|
|
|
|
e1, e2 = elements[0:2]
|
|
if type_elements == "paginatedItems":
|
|
e1, e2 = e1["node"], e2["node"]
|
|
|
|
e1_url = f'{vrt_be.BASE_URL}{e1["playAction"]["pageUrl"]}'
|
|
e1_index = vrt_be.get_episode_index(e1["primaryMeta"], e1_url)
|
|
e2_url = f'{vrt_be.BASE_URL}{e2["playAction"]["pageUrl"]}'
|
|
e2_index = vrt_be.get_episode_index(e2["primaryMeta"], e2_url)
|
|
return e1_index < e2_index
|
|
|
|
@staticmethod
|
|
def clean_title(title):
|
|
title = title.lower().replace(' ', '-')
|
|
title = quote(title)
|
|
title = re.sub(r'%[0-9a-fA-F]{2}', '', title)
|
|
return title
|
|
|
|
@staticmethod
|
|
def radio_handler(collection_name, component_id):
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query component($componentId: ID!, $lazyItemCount: Int = ' +
|
|
str(vrt_be.PAGE_SIZE) +
|
|
', $after: ID, $before: ID) {\n component(id: $componentId) {\n __typename\n ... on ContainerNavigationItem {\n __typename\n objectId\n componentId\n title\n components {\n __typename\n ... on PaginatedTileList {\n ...basicPaginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...basicStaticTileListFragment\n __typename\n }\n ... on ElectronicProgramGuideSchedule {\n ...epgFragment\n __typename\n }\n ... on Chat {\n __typename\n chatId\n expires\n objectId\n ...componentTrackingDataFragment\n }\n ... on Text {\n ...textFragment\n __typename\n }\n ... on PresentersList {\n __typename\n objectId\n presenters {\n title\n __typename\n }\n }\n ... on NoContent {\n ...noContentFragment\n __typename\n }\n }\n }\n }\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment noContentFragment on NoContent {\n __typename\n objectId\n title\n text\n noContentType\n actionItems {\n ...actionItemFragment\n __typename\n }\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment textFragment on Text {\n __typename\n objectId\n html\n}\nfragment basicPaginatedTileListFragment on PaginatedTileList {\n __typename\n objectId\n listId\n displayType\n expires\n tileVariant\n tileContentType\n tileOrientation\n title\n paginatedItems(first: $lazyItemCount, after: $after, before: $before) {\n __typename\n edges {\n __typename\n cursor\n node {\n __typename\n ...tileFragment\n }\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment basicStaticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n displayType\n expires\n tileVariant\n tileContentType\n tileOrientation\n title\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment epgFragment on ElectronicProgramGuideSchedule {\n __typename\n objectId\n expires\n current {\n tile {\n ...tileFragment\n __typename\n }\n __typename\n }\n next {\n ...basicPaginatedTileListFragment\n __typename\n }\n previous {\n ...basicPaginatedTileListFragment\n __typename\n }\n}',
|
|
'operationName': 'component',
|
|
'variables': {'componentId': component_id}
|
|
}
|
|
).content.decode())
|
|
|
|
response = response["data"]["component"]
|
|
episode_index = 0
|
|
collection = []
|
|
|
|
for component in response.get("components", []):
|
|
if component["__typename"] == "StaticTileList":
|
|
for item in component["items"]:
|
|
episode_index += 1
|
|
|
|
check = check_range(False, None, episode_index)
|
|
if check is True:
|
|
continue
|
|
elif check is False:
|
|
return collection
|
|
|
|
collection.append(BaseElement(
|
|
url=f'{vrt_be.BASE_URL}{item["action"]["pageLink"]}',
|
|
collection=join(join(
|
|
str(builtins.CONFIG["DOWNLOAD_COMMANDS"]["OUTPUT_MEDIA_PATH"]),
|
|
vrt_be.__name__
|
|
), collection_name),
|
|
element=f'Radio_{episode_index}'
|
|
f'_'
|
|
f'{get_valid_filename(item["title"])}'
|
|
))
|
|
|
|
return collection
|
|
return None
|
|
|
|
@staticmethod
|
|
def container_navigation_handler(collection_name, container, selected_season_name, fragment, url):
|
|
collection = []
|
|
if fragment is not None:
|
|
collection_name = join(collection_name, get_valid_filename(fragment))
|
|
if selected_season_name is not None:
|
|
collection_name = join(collection_name, get_valid_filename(selected_season_name))
|
|
|
|
for i1 in container["items"]:
|
|
collection_index = vrt_be.get_label_index(i1["title"])
|
|
if collection_index is None and vrt_be.clean_title(i1["title"]) != fragment:
|
|
continue
|
|
|
|
if "/luister/radio/" in url and i1.get("components", None) is None:
|
|
return vrt_be.radio_handler(collection_name, i1["componentId"])
|
|
|
|
season_index = 0
|
|
for c1 in i1["components"]:
|
|
seasons = []
|
|
ignore_index = False
|
|
if "/podcasts/" in url in url:
|
|
ignore_index = True
|
|
|
|
if len(c1.get("paginatedItems", [])) > 0:
|
|
if collection_index is None:
|
|
collection_index = vrt_be.get_label_index(c1["title"])
|
|
if collection_index is not None:
|
|
season_index = collection_index
|
|
else:
|
|
season_index += 1
|
|
ignore_index = True
|
|
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query PaginatedTileListPage($listId: ID!, $lazyItemCount: Int = ' +
|
|
str(vrt_be.PAGE_SIZE) +
|
|
', $after: ID, $before: ID) {\n list(listId: $listId) {\n __typename\n ... on PaginatedTileList {\n ...paginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...staticTileListFragment\n __typename\n }\n }\n}\nfragment staticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n title\n description\n tileContentType\n tileOrientation\n displayType\n expires\n tileVariant\n sort {\n icon\n order\n title\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n description\n image {\n ...imageFragment\n __typename\n }\n compactLayout\n backgroundColor\n textTheme\n title\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n bannerSize\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment paginatedTileListFragment on PaginatedTileList {\n __typename\n objectId\n listId\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n backgroundColor\n compactLayout\n description\n image {\n ...imageFragment\n __typename\n }\n titleArt {\n ...imageFragment\n __typename\n }\n textTheme\n title\n __typename\n }\n bannerSize\n displayType\n expires\n tileVariant\n paginatedItems(first: $lazyItemCount, after: $after, before: $before) {\n __typename\n edges {\n __typename\n cursor\n node {\n __typename\n ...tileFragment\n }\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n sort {\n icon\n order\n title\n __typename\n }\n tileContentType\n tileOrientation\n title\n description\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}',
|
|
'operationName': 'PaginatedTileListPage',
|
|
'variables': {'listId': c1["listId"]}
|
|
}
|
|
).content.decode())
|
|
response = response["data"]["list"]
|
|
|
|
seasons.append((season_index, response))
|
|
|
|
elif len(c1.get("items", [])) > 0:
|
|
tuples = [
|
|
(vrt_be.get_label_index(i["title"]), i)
|
|
for i in c1["items"]
|
|
]
|
|
seasons = sorted([
|
|
(index, item) for index, item in tuples
|
|
if index is not None], key=lambda m: m[0]
|
|
) + [(index, item) for index, item in tuples if index is None]
|
|
|
|
if len(seasons) == 0:
|
|
seasons = [(vrt_be.get_label_index(i1["title"]), c1)]
|
|
|
|
for season_index, season in seasons:
|
|
if season_index is None:
|
|
if (
|
|
selected_season_name is not None and
|
|
vrt_be.clean_title(season["title"]).startswith(selected_season_name)
|
|
):
|
|
pass
|
|
else:
|
|
continue
|
|
if selected_season_name is not None and season_index is not None:
|
|
continue
|
|
|
|
try:
|
|
list_id = [c for c in season["components"] if len(c.get("listId", "")) > 0][0]["listId"]
|
|
except:
|
|
list_id = season["listId"]
|
|
|
|
if season_index is not None:
|
|
check = check_range(True, season_index, None)
|
|
if check is True:
|
|
continue
|
|
elif check is False:
|
|
return collection
|
|
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query ProgramSeasonEpisodeList($listId: ID!, $sort: SortInput, $lazyItemCount: Int = ' +
|
|
str(vrt_be.PAGE_SIZE) +
|
|
', $after: ID, $before: ID) {\n list(listId: $listId, sort: $sort) {\n __typename\n ... on PaginatedTileList {\n ...paginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...staticTileListFragment\n __typename\n }\n }\n}\nfragment staticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n title\n description\n tileContentType\n tileOrientation\n displayType\n expires\n tileVariant\n sort {\n icon\n order\n title\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n description\n image {\n ...imageFragment\n __typename\n }\n compactLayout\n backgroundColor\n textTheme\n title\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n bannerSize\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment paginatedTileListFragment on PaginatedTileList {\n __typename\n objectId\n listId\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n backgroundColor\n compactLayout\n description\n image {\n ...imageFragment\n __typename\n }\n titleArt {\n ...imageFragment\n __typename\n }\n textTheme\n title\n __typename\n }\n bannerSize\n displayType\n expires\n tileVariant\n paginatedItems(first: $lazyItemCount, after: $after, before: $before) {\n __typename\n edges {\n __typename\n cursor\n node {\n __typename\n ...tileFragment\n }\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n sort {\n icon\n order\n title\n __typename\n }\n tileContentType\n tileOrientation\n title\n description\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}',
|
|
'operationName': 'ProgramSeasonEpisodeList',
|
|
'variables': {'listId': list_id}
|
|
}
|
|
).content.decode())
|
|
|
|
response = response["data"]["list"]
|
|
is_asc = None
|
|
if ignore_index:
|
|
is_asc = True
|
|
|
|
episode_index = 0
|
|
if response.get("paginatedItems", None) is not None:
|
|
while True:
|
|
edges = response["paginatedItems"].get("edges", [])
|
|
if is_asc is None:
|
|
is_asc = vrt_be.check_order("paginatedItems", edges)
|
|
|
|
for edge in edges:
|
|
e = edge["node"]
|
|
if e.get("playAction", None) is None:
|
|
continue
|
|
|
|
episode_url = f'{vrt_be.BASE_URL}{e["playAction"]["pageUrl"]}'
|
|
if ignore_index:
|
|
episode_index += 1
|
|
else:
|
|
episode_index = vrt_be.get_episode_index(e["primaryMeta"], episode_url)
|
|
|
|
check = check_range(False, season_index, episode_index, is_asc)
|
|
if check is True:
|
|
continue
|
|
elif check is False:
|
|
return collection
|
|
|
|
collection.append(BaseElement(
|
|
url=episode_url,
|
|
collection=join(
|
|
join(
|
|
str(builtins.CONFIG["DOWNLOAD_COMMANDS"]["OUTPUT_MEDIA_PATH"]),
|
|
vrt_be.__name__
|
|
),
|
|
collection_name if season_index is None else
|
|
join(collection_name, f'Season_{season_index}')
|
|
),
|
|
element=f'Episode_{episode_index}'
|
|
f'_'
|
|
f'{get_valid_filename(e["title"])}'
|
|
))
|
|
|
|
page_info = response["paginatedItems"]["pageInfo"]
|
|
if page_info["hasNextPage"] is True:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query ProgramSeasonEpisodeList($listId: ID!, $sort: SortInput, $lazyItemCount: Int = ' +
|
|
str(vrt_be.PAGE_SIZE) +
|
|
', $after: ID, $before: ID) {\n list(listId: $listId, sort: $sort) {\n __typename\n ... on PaginatedTileList {\n ...paginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...staticTileListFragment\n __typename\n }\n }\n}\nfragment staticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n title\n description\n tileContentType\n tileOrientation\n displayType\n expires\n tileVariant\n sort {\n icon\n order\n title\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n description\n image {\n ...imageFragment\n __typename\n }\n compactLayout\n backgroundColor\n textTheme\n title\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n bannerSize\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment paginatedTileListFragment on PaginatedTileList {\n __typename\n objectId\n listId\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n backgroundColor\n compactLayout\n description\n image {\n ...imageFragment\n __typename\n }\n titleArt {\n ...imageFragment\n __typename\n }\n textTheme\n title\n __typename\n }\n bannerSize\n displayType\n expires\n tileVariant\n paginatedItems(first: $lazyItemCount, after: $after, before: $before) {\n __typename\n edges {\n __typename\n cursor\n node {\n __typename\n ...tileFragment\n }\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n sort {\n icon\n order\n title\n __typename\n }\n tileContentType\n tileOrientation\n title\n description\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}',
|
|
'operationName': 'ProgramSeasonEpisodeList',
|
|
'variables': {'listId': list_id, 'after': page_info["endCursor"]}
|
|
}
|
|
).content.decode())
|
|
response = response["data"]["list"]
|
|
continue
|
|
break
|
|
continue
|
|
|
|
elif response.get("items", None) is not None:
|
|
if is_asc is None:
|
|
is_asc = vrt_be.check_order("items", response["items"])
|
|
|
|
for e in response["items"]:
|
|
if e.get("playAction", None) is None:
|
|
continue
|
|
|
|
episode_url = f'{vrt_be.BASE_URL}{e["playAction"]["pageUrl"]}'
|
|
if ignore_index:
|
|
episode_index += 1
|
|
else:
|
|
episode_index = vrt_be.get_episode_index(e["primaryMeta"], episode_url)
|
|
|
|
check = check_range(False, season_index, episode_index, is_asc)
|
|
if check is True:
|
|
continue
|
|
elif check is False:
|
|
return collection
|
|
|
|
collection.append(BaseElement(
|
|
url=episode_url,
|
|
collection=join(
|
|
join(
|
|
str(builtins.CONFIG["DOWNLOAD_COMMANDS"]["OUTPUT_MEDIA_PATH"]),
|
|
vrt_be.__name__
|
|
),
|
|
collection_name if season_index is None else
|
|
join(collection_name, f'Season_{season_index}')
|
|
),
|
|
element=f'Episode_{episode_index}'
|
|
f'_'
|
|
f'{get_valid_filename(e["title"])}'
|
|
))
|
|
continue
|
|
|
|
return None
|
|
return collection
|
|
|
|
@staticmethod
|
|
def collection_handler(collection_url, season_name, fragment):
|
|
if "/a-z/" in collection_url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query VideoProgramPage($pageId: ID!, $lazyItemCount: Int = ' +
|
|
str(vrt_be.PAGE_SIZE) +
|
|
', $after: ID, $before: ID) {\n page(id: $pageId) {\n ... on ProgramPage {\n objectId\n permalink\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n ...trackingDataFragment\n __typename\n }\n ldjson\n components {\n __typename\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on Banner {\n ...bannerFragment\n __typename\n }\n ... on PageHeader {\n ...pageHeaderFragment\n __typename\n }\n ... on ContainerNavigation {\n objectId\n navigationType\n items {\n objectId\n title\n active\n components {\n __typename\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on PaginatedTileList {\n ...paginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...staticTileListFragment\n __typename\n }\n ... on LazyTileList {\n objectId\n title\n listId\n __typename\n }\n ... on Banner {\n ...bannerFragment\n __typename\n }\n ... on IComponent {\n ... on Text {\n ...textFragment\n __typename\n }\n ... on TagsList {\n objectId\n title\n tags {\n name\n title\n category\n __typename\n }\n __typename\n }\n ... on PresentersList {\n objectId\n title\n presenters {\n title\n type\n __typename\n }\n __typename\n }\n ... on ContainerNavigation {\n objectId\n navigationType\n items {\n objectId\n title\n components {\n __typename\n ... on Component {\n ... on PaginatedTileList {\n ...paginatedTileListFragment\n __typename\n }\n ... on StaticTileList {\n ...staticTileListFragment\n __typename\n }\n ... on LazyTileList {\n objectId\n title\n listId\n __typename\n }\n __typename\n }\n }\n __typename\n }\n __typename\n }\n __typename\n }\n }\n __typename\n }\n __typename\n }\n ...paginatedTileListFragment\n }\n __typename\n }\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment staticTileListFragment on StaticTileList {\n __typename\n objectId\n listId\n title\n description\n tileContentType\n tileOrientation\n displayType\n expires\n tileVariant\n sort {\n icon\n order\n title\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n description\n image {\n ...imageFragment\n __typename\n }\n compactLayout\n backgroundColor\n textTheme\n title\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n bannerSize\n items {\n ...tileFragment\n __typename\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment paginatedTileListFragment on PaginatedTileList {\n __typename\n objectId\n listId\n actionItems {\n ...actionItemFragment\n __typename\n }\n banner {\n actionItems {\n ...actionItemFragment\n __typename\n }\n backgroundColor\n compactLayout\n description\n image {\n ...imageFragment\n __typename\n }\n titleArt {\n ...imageFragment\n __typename\n }\n textTheme\n title\n __typename\n }\n bannerSize\n displayType\n expires\n tileVariant\n paginatedItems(first: $lazyItemCount, after: $after, before: $before) {\n __typename\n edges {\n __typename\n cursor\n node {\n __typename\n ...tileFragment\n }\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n sort {\n icon\n order\n title\n __typename\n }\n tileContentType\n tileOrientation\n title\n description\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment pageHeaderFragment on PageHeader {\n objectId\n title\n richShortDescription {\n __typename\n html\n }\n richDescription {\n __typename\n html\n }\n announcementValue\n announcementType\n mostRelevantEpisodeTile {\n __typename\n objectId\n tile {\n ...tileFragment\n __typename\n }\n title\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n secondaryMeta {\n longValue\n shortValue\n type\n value\n __typename\n }\n image {\n objectId\n alt\n focalPoint\n templateUrl\n __typename\n }\n categories {\n category\n name\n title\n __typename\n }\n presenters {\n title\n __typename\n }\n brands {\n name\n title\n __typename\n }\n brandsLogos {\n brand\n brandTitle\n logos {\n mono\n primary\n type\n __typename\n }\n __typename\n }\n}\nfragment bannerFragment on Banner {\n __typename\n objectId\n brand\n countdown {\n date\n __typename\n }\n richDescription {\n __typename\n text\n }\n ctaText\n image {\n objectId\n templateUrl\n alt\n focalPoint\n __typename\n }\n title\n compactLayout\n textTheme\n backgroundColor\n style\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n titleArt {\n objectId\n templateUrl\n __typename\n }\n labelMeta {\n __typename\n type\n value\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n}\nfragment textFragment on Text {\n __typename\n objectId\n html\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}',
|
|
'operationName': 'VideoProgramPage',
|
|
'variables': {'pageId': f'/vrtnu/{collection_url.split("/vrtmax/")[1]}.model.json'}
|
|
}
|
|
).content.decode())
|
|
|
|
elif "/podcasts/" in collection_url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query PodcastProgramPage($pageId: ID!) {\n page(id: $pageId) {\n ... on PodcastProgramPage {\n objectId\n permalink\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n ...trackingDataFragment\n __typename\n }\n ldjson\n components {\n __typename\n ... on IComponent {\n ...pageHeaderFragment\n ... on ContainerNavigation {\n objectId\n navigationType\n items {\n objectId\n title\n active\n active\n components {\n __typename\n ... on PaginatedTileList {\n __typename\n objectId\n sort {\n order\n __typename\n }\n title\n listId\n paginatedItems(first: 20) {\n edges {\n node {\n __typename\n ...tileFragment\n }\n __typename\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n __typename\n }\n }\n ... on IComponent {\n ... on Text {\n ...textFragment\n __typename\n }\n ... on TagsList {\n objectId\n title\n tags {\n name\n title\n category\n __typename\n }\n __typename\n }\n ... on PresentersList {\n objectId\n title\n presenters {\n title\n type\n __typename\n }\n __typename\n }\n ... on ContainerNavigation {\n objectId\n navigationType\n items {\n objectId\n title\n components {\n __typename\n ... on Component {\n ... on PaginatedTileList {\n __typename\n objectId\n sort {\n order\n __typename\n }\n title\n listId\n paginatedItems(first: 20) {\n edges {\n node {\n __typename\n ...tileFragment\n }\n cursor\n __typename\n }\n pageInfo {\n __typename\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n __typename\n }\n }\n ... on LazyTileList {\n objectId\n title\n listId\n __typename\n }\n __typename\n }\n }\n __typename\n }\n __typename\n }\n __typename\n }\n }\n __typename\n }\n __typename\n }\n __typename\n }\n }\n __typename\n }\n __typename\n }\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment textFragment on Text {\n __typename\n objectId\n html\n}\nfragment pageHeaderFragment on PageHeader {\n objectId\n title\n richShortDescription {\n __typename\n html\n }\n richDescription {\n __typename\n html\n }\n announcementValue\n announcementType\n mostRelevantEpisodeTile {\n __typename\n objectId\n tile {\n ...tileFragment\n __typename\n }\n title\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n secondaryMeta {\n longValue\n shortValue\n type\n value\n __typename\n }\n image {\n objectId\n alt\n focalPoint\n templateUrl\n __typename\n }\n categories {\n category\n name\n title\n __typename\n }\n presenters {\n title\n __typename\n }\n brands {\n name\n title\n __typename\n }\n brandsLogos {\n brand\n brandTitle\n logos {\n mono\n primary\n type\n __typename\n }\n __typename\n }\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}',
|
|
'operationName': 'PodcastProgramPage',
|
|
'variables': {'pageId': f'/vrtnu/{collection_url.split("/vrtmax/")[1]}.model.json'}
|
|
}
|
|
).content.decode())
|
|
|
|
elif "/luister/radio/" in collection_url:
|
|
response = json.loads(requests.post(
|
|
vrt_be.GRAPHQL_URL,
|
|
headers={'x-vrt-client-name': 'WEB'},
|
|
json={
|
|
'query': 'query RadioProgramPage($pageId: ID!) {\n page(id: $pageId) {\n __typename\n ... on RadioProgramPage {\n __typename\n objectId\n title\n brand\n permalink\n seo {\n ...seoFragment\n __typename\n }\n socialSharing {\n ...socialSharingFragment\n __typename\n }\n trackingData {\n ...trackingDataFragment\n __typename\n }\n components {\n __typename\n ... on PageHeader {\n ...pageHeaderFragment\n __typename\n }\n ... on ContainerNavigation {\n __typename\n objectId\n navigationType\n items {\n __typename\n objectId\n componentId\n title\n active\n }\n }\n }\n }\n }\n}\nfragment metaFragment on MetaDataItem {\n __typename\n type\n value\n shortValue\n longValue\n}\nfragment actionItemFragment on ActionItem {\n __typename\n objectId\n accessibilityLabel\n action {\n ...actionFragment\n __typename\n }\n active\n icon\n iconPosition\n icons {\n __typename\n position\n ... on DesignSystemIcon {\n value {\n name\n __typename\n }\n __typename\n }\n }\n mode\n objectId\n title\n}\nfragment actionFragment on Action {\n __typename\n ... on FavoriteAction {\n favorite\n id\n programUrl\n programWhatsonId\n title\n __typename\n }\n ... on ListDeleteAction {\n listName\n id\n listId\n title\n __typename\n }\n ... on ListTileDeletedAction {\n listName\n id\n listId\n __typename\n }\n ... on PodcastEpisodeListenAction {\n id: audioId\n podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on EpisodeWatchAction {\n id: videoId\n videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n ... on LinkAction {\n id: linkId\n linkId\n link\n linkType\n openExternally\n passUserIdentity\n linkTokens {\n __typename\n placeholder\n value\n }\n __typename\n }\n ... on ShareAction {\n title\n url\n __typename\n }\n ... on SwitchTabAction {\n referencedTabId\n mediaType\n link\n __typename\n }\n ... on RadioEpisodeListenAction {\n streamId\n pageLink\n startDate\n __typename\n }\n ... on LiveListenAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n ... on LiveWatchAction {\n streamId\n livestreamPageLink\n startDate\n startOver\n endDate\n __typename\n }\n}\nfragment imageFragment on Image {\n __typename\n objectId\n alt\n title\n focalPoint\n templateUrl\n}\nfragment tileFragment on Tile {\n ... on IIdentifiable {\n __typename\n objectId\n }\n ... on IComponent {\n ...componentTrackingDataFragment\n __typename\n }\n ... on ITile {\n description\n title\n active\n action {\n ...actionFragment\n __typename\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n image {\n ...imageFragment\n __typename\n }\n primaryMeta {\n ...metaFragment\n __typename\n }\n secondaryMeta {\n ...metaFragment\n __typename\n }\n tertiaryMeta {\n ...metaFragment\n __typename\n }\n indexMeta {\n __typename\n type\n value\n }\n statusMeta {\n __typename\n type\n value\n }\n labelMeta {\n __typename\n type\n value\n }\n __typename\n }\n ... on ContentTile {\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n ... on BannerTile {\n compactLayout\n backgroundColor\n textTheme\n brand\n brandLogos {\n ...brandLogosFragment\n __typename\n }\n ctaText\n passUserIdentity\n titleArt {\n objectId\n templateUrl\n __typename\n }\n __typename\n }\n ... on EpisodeTile {\n description\n formattedDuration\n available\n chapterStart\n action {\n ...actionFragment\n __typename\n }\n playAction: watchAction {\n pageUrl: videoUrl\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n episode {\n __typename\n objectId\n program {\n __typename\n objectId\n link\n }\n }\n \n __typename\n }\n ... on PodcastEpisodeTile {\n formattedDuration\n available\n programLink: podcastEpisode {\n objectId\n podcastProgram {\n objectId\n link\n __typename\n }\n __typename\n }\n playAction: listenAction {\n pageUrl: podcastEpisodeLink\n resumePointProgress\n resumePointTotal\n completed\n __typename\n }\n __typename\n }\n ... on PodcastProgramTile {\n link\n __typename\n }\n ... on ProgramTile {\n link\n __typename\n }\n ... on AudioLivestreamTile {\n brand\n brandsLogos {\n brand\n brandTitle\n logos {\n ...brandLogosFragment\n __typename\n }\n __typename\n }\n __typename\n }\n ... on LivestreamTile {\n description\n __typename\n }\n ... on ButtonTile {\n icon\n iconPosition\n mode\n __typename\n }\n ... on RadioEpisodeTile {\n action {\n ...actionFragment\n __typename\n }\n available\n \n formattedDuration\n ...componentTrackingDataFragment\n __typename\n }\n ... on SongTile {\n startDate\n formattedStartDate\n endDate\n __typename\n }\n ... on RadioProgramTile {\n objectId\n __typename\n }\n}\nfragment componentTrackingDataFragment on IComponent {\n trackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n}\nfragment brandLogosFragment on Logo {\n colorOnColor\n height\n mono\n primary\n type\n width\n}\nfragment seoFragment on SeoProperties {\n __typename\n title\n description\n}\nfragment socialSharingFragment on SocialSharingProperties {\n __typename\n title\n description\n image {\n __typename\n objectId\n templateUrl\n }\n}\nfragment trackingDataFragment on PageTrackingData {\n data\n perTrigger {\n trigger\n data\n template {\n id\n __typename\n }\n __typename\n }\n}\nfragment pageHeaderFragment on PageHeader {\n objectId\n title\n richShortDescription {\n __typename\n html\n }\n richDescription {\n __typename\n html\n }\n announcementValue\n announcementType\n mostRelevantEpisodeTile {\n __typename\n objectId\n tile {\n ...tileFragment\n __typename\n }\n title\n }\n actionItems {\n ...actionItemFragment\n __typename\n }\n secondaryMeta {\n longValue\n shortValue\n type\n value\n __typename\n }\n image {\n objectId\n alt\n focalPoint\n templateUrl\n __typename\n }\n categories {\n category\n name\n title\n __typename\n }\n presenters {\n title\n __typename\n }\n brands {\n name\n title\n __typename\n }\n brandsLogos {\n brand\n brandTitle\n logos {\n mono\n primary\n type\n __typename\n }\n __typename\n }\n}',
|
|
'operationName': 'RadioProgramPage',
|
|
'variables': {'pageId': f'/vrtnu/{collection_url.split("/vrtmax/")[1]}/'}
|
|
}
|
|
).content.decode())
|
|
else:
|
|
return None
|
|
|
|
response = response["data"]["page"]["components"]
|
|
try:
|
|
collection_name = [c for c in response if c["__typename"] == "PageHeader"][0]["title"]
|
|
except:
|
|
collection_name = clean_url(collection_url).rstrip("/").split("/")[-1]
|
|
collection_name = get_valid_filename(collection_name)
|
|
|
|
for c1 in response:
|
|
if c1["__typename"] == "PaginatedTileList":
|
|
c1["components"] = [c1]
|
|
return vrt_be.container_navigation_handler(
|
|
collection_name, {"items": [c1]},
|
|
season_name, fragment, collection_url
|
|
)
|
|
|
|
if c1["__typename"] == "ContainerNavigation":
|
|
if fragment is None:
|
|
return None
|
|
return vrt_be.container_navigation_handler(
|
|
collection_name, c1, season_name,
|
|
fragment, collection_url
|
|
)
|
|
|
|
return None
|
|
|
|
@staticmethod
|
|
def get_collection_elements(collection_url):
|
|
collection_url = collection_url.rstrip('/')
|
|
if "/vrtmax/" not in collection_url:
|
|
return None
|
|
|
|
fragment = None
|
|
if "#" in collection_url:
|
|
fragment = urlparse(collection_url).fragment
|
|
collection_url = collection_url.split(f'#{fragment}')[0].rstrip("/")
|
|
|
|
season_name = None
|
|
if "?" in collection_url and "seizoen=" in collection_url:
|
|
season_name = parse_qs(urlparse(collection_url).query)["seizoen"][0]
|
|
if "seizoen-" in season_name.lower():
|
|
return None
|
|
collection_url = collection_url.split('?')[0].rstrip("/")
|
|
|
|
for p, i in [
|
|
("/a-z/", 0), ("/podcasts/", 2), ("/livestream/audio/", -1),
|
|
("/livestream/video/", -1), ("/luister/radio/", 1)
|
|
]:
|
|
if p in collection_url:
|
|
if 0 <= i == collection_url.split(p)[1].count("/"):
|
|
return vrt_be.collection_handler(collection_url, season_name, fragment)
|
|
return [BaseElement(url=collection_url)]
|
|
return None
|