Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugin.video.vrt.nu@krypton] 2.5.26 #4391

Merged
merged 1 commit into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions plugin.video.vrt.nu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ leave a message at [our Facebook page](https://facebook.com/kodivrtnu/).
</table>

## Releases
### v2.5.26 (2023-09-22)
- Fix program listings (@mediaminister)
- Add extra content to program listings (@mediaminister)

### v2.5.25 (2023-09-14)
- Fix episode listings and featured menu (@mediaminister)

Expand Down
6 changes: 5 additions & 1 deletion plugin.video.vrt.nu/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.vrt.nu" name="VRT MAX" version="2.5.25" provider-name="Martijn Moreel, dagwieers, mediaminister">
<addon id="plugin.video.vrt.nu" name="VRT MAX" version="2.5.26" provider-name="Martijn Moreel, dagwieers, mediaminister">
<requires>
<import addon="resource.images.studios.white" version="0.0.22"/>
<import addon="script.module.beautifulsoup4" version="4.6.2"/>
Expand Down Expand Up @@ -42,6 +42,10 @@
<website>https://github.com/add-ons/plugin.video.vrt.nu/wiki</website>
<source>https://github.com/add-ons/plugin.video.vrt.nu</source>
<news>
v2.5.26 (2023-09-22)
- Fix program listings
- Add extra content to program listings

v2.5.25 (2023-09-14)
- Fix episode listings and featured menu

Expand Down
234 changes: 201 additions & 33 deletions plugin.video.vrt.nu/resources/lib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,54 @@ def get_next_info(episode_id):
return next_info


def get_stream_id_data(vrtmax_url):
"""Get stream_id from from GraphQL API"""
from tokenresolver import TokenResolver
access_token = TokenResolver().get_token('vrtnu-site_profile_at')
data_json = {}
if access_token:
headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json',
}
page_id = vrtmax_url.split('www.vrt.be')[1].replace('/vrtmax/', '/vrtnu/').rstrip('/') + '.model.json'
graphql_query = """
query StreamId($pageId: ID!) {
page(id: $pageId) {
... on IPage {
... on LivestreamPage {
player {
watchAction {
... on LiveWatchAction {
streamId
}
}
}
}
}
... on EpisodePage {
episode {
watchAction {
streamId
}
}
}
}
}
"""
payload = {
'operationName': 'StreamId',
'variables': {
'pageId': page_id
},
'query': graphql_query,
}
from json import dumps
data = dumps(payload).encode('utf-8')
data_json = get_url_json(url=GRAPHQL_URL, cache=None, headers=headers, data=data, raise_errors='all')
return data_json


def get_single_episode_data(episode_id):
"""Get single episode data from GraphQL API"""
from tokenresolver import TokenResolver
Expand Down Expand Up @@ -326,6 +374,110 @@ def get_latest_episode_data(program_name):
from tokenresolver import TokenResolver
access_token = TokenResolver().get_token('vrtnu-site_profile_at')
data_json = {}
if access_token:
headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json',
}
graphql_query = """
query VideoProgramPage($pageId: ID!, $lazyItemCount: Int = 500, $after: ID) {
page(id: $pageId) {
... on ProgramPage {
components {
__typename
... on PageHeader {
mostRelevantEpisodeTile {
__typename
title
tile {
...episodeTile
__typename
}
__typename
}
__typename
}
... on ContainerNavigation {
items {
title
components {
__typename
... on PaginatedTileList {
__typename
paginatedItems(first: $lazyItemCount, after: $after) {
__typename
edges {
__typename
cursor
node {
__typename
... on EpisodeTile {
id
description
...episodeTile
}
}
}
}
}
... on ContainerNavigation {
items {
title
components {
__typename
... on PaginatedTileList {
__typename
paginatedItems(first: $lazyItemCount, after: $after) {
__typename
edges {
__typename
cursor
node {
__typename
... on EpisodeTile {
id
description
...episodeTile
}
}
}
}
}
}
}
__typename
}
}
__typename
}
__typename
}
}
__typename
}
__typename
}
}
%s
""" % EPISODE_TILE
payload = {
'operationName': 'VideoProgramPage',
'variables': {
'pageId': '/vrtnu/a-z/{}.model.json'.format(program_name),
},
'query': graphql_query,
}
from json import dumps
data = dumps(payload).encode('utf-8')
data_json = get_url_json(url=GRAPHQL_URL, cache=None, headers=headers, data=data, raise_errors='all')
return data_json


def get_seasons_data(program_name):
"""Get seasons data from GraphQL API"""
from tokenresolver import TokenResolver
access_token = TokenResolver().get_token('vrtnu-site_profile_at')
data_json = {}
if access_token:
headers = {
'Authorization': 'Bearer ' + access_token,
Expand Down Expand Up @@ -1006,7 +1158,7 @@ def get_offline_programs(end_cursor='', use_favorites=False):

def get_episodes(program_name, season_name=None, end_cursor=''):
"""Get episodes"""
sort = 'label'
sort = 'unsorted'
ascending = True
content = 'files'
page_size = get_setting_int('itemsperpage', default=50)
Expand All @@ -1021,7 +1173,10 @@ def get_episodes(program_name, season_name=None, end_cursor=''):
return seasons, sort, ascending, content

if program_name and season_name:
list_id = 'static:/vrtnu/a-z/{}/{}.episodes-list.json'.format(program_name, season_name)
if season_name.startswith('parsys'):
list_id = 'static:/vrtnu/a-z/{}.model.json@{}'.format(program_name, season_name)
else:
list_id = 'static:/vrtnu/a-z/{}/{}.episodes-list.json'.format(program_name, season_name)
api_data = get_paginated_episodes(list_id=list_id, page_size=page_size, end_cursor=end_cursor)
episodes, sort, ascending = convert_episodes(api_data, destination='programs', program_name=program_name, season_name=season_name)
return episodes, sort, ascending, 'episodes'
Expand All @@ -1032,69 +1187,81 @@ def convert_seasons(api_data, program_name):
"""Convert seasons"""
seasons = []
for season in api_data:
season_title = season.get('title')
season_name = season.get('name')
path = url_for('programs', program_name=program_name, season_name=season_name)
seasons.append(
TitleItem(
label=season_title,
path=path,
info_dict={
'title': season_title,
'mediatype': 'season',
},
is_playable=False,
if season.get('name') == 'mostRelevantEpisode':
_, _, _, title_item = convert_episode(season.get('episode'))
title_item.label = '[B]{}:[/B] {}'.format(season.get('title'), title_item.label)
title_item.info_dict['title'] = '[B]{}:[/B] {}'.format(season.get('title'), title_item.info_dict.get('title'))
seasons.append(title_item)
else:
season_title = season.get('title')
season_name = season.get('name')
path = url_for('programs', program_name=program_name, season_name=season_name)
seasons.append(
TitleItem(
label=season_title,
path=path,
info_dict={
'title': season_title,
'mediatype': 'season',
},
is_playable=False,
)
)
)
return seasons


def create_season_dict(data_json):
"""Create season dictionary"""
season_title = data_json.get('title')
season_dict = {}
# title
season_dict['title'] = data_json.get('title') or data_json.get('mostRelevantEpisodeTile').get('title')

# list_id
if data_json.get('components'):
list_id = data_json.get('components')[0].get('listId')
elif data_json.get('mostRelevantEpisodeTile'):
list_id = 'mostRelevantEpisode'
season_dict['episode'] = data_json.get('mostRelevantEpisodeTile')
else:
list_id = data_json.get('listId')

# season name
if '.episodes-list.json' in list_id:
season_name = list_id.split('.episodes-list.json')[0].split('/')[-1]
season_dict['name'] = list_id.split('.episodes-list.json')[0].split('/')[-1]
else:
season_name = list_id.split('_')[-1]
return {'title': season_title, 'name': season_name}
season_dict['name'] = list_id.split('@')[-1]
return season_dict


def get_seasons(program_name):
"""Get seasons"""
seasons = []
# FIXME: The current codebase only supports seasons and not the extra content. So we need to select seasons using a whitelist.
whitelist = ['Afleveringen', 'Alle seizoenen', 'Journaals', 'Reeksen', 'Docu']
components = get_latest_episode_data(program_name).get('data').get('page').get('components')
components = get_seasons_data(program_name).get('data').get('page').get('components')
# Extract season data from components
for component in components:
# Check component type
if component.get('navigationType') == 'bar':
# Get items
for item in component.get('items'):
# Select whitelist item
if item.get('title') in whitelist:
# Get components
for nested_component in item.get('components'):
# Append component
components.append(nested_component)
# Get components
for nested_component in item.get('components'):
# Append component
components.append(nested_component)
elif component.get('navigationType') == 'select':
# Get items
for item in component.get('items'):
# Store season
seasons.append(create_season_dict(item))
# Extraction done, remove component
components.remove(component)
if item.get('title'):
seasons.append(create_season_dict(item))
elif component.get('__typename') == 'PaginatedTileList' and component.get('tileContentType') == 'episode':
# Store season
if component.get('title'):
seasons.append(create_season_dict(component))
elif component.get('__typename') == 'PageHeader' and component.get('mostRelevantEpisodeTile'):
seasons.append(create_season_dict(component))
# Extraction done, remove component
components.remove(component)
return seasons


def get_featured_data():
"""Get featured data"""
from tokenresolver import TokenResolver
Expand Down Expand Up @@ -1178,6 +1345,7 @@ def get_featured_data():
data_json = get_url_json(url=GRAPHQL_URL, cache=None, headers=headers, data=data, raise_errors='all')
return data_json


def get_featured(feature=None, end_cursor=''):
"""Get featured menu items"""
content = 'files'
Expand Down
6 changes: 3 additions & 3 deletions plugin.video.vrt.nu/resources/lib/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@
{
'id': '1H',
'name': 'canvas',
'label': 'Canvas',
'label': 'VRT Canvas',
'studio': 'Canvas',
'live_stream': 'https://www.vrt.be/vrtmax/livestream/video/canvas/',
'live_stream': 'https://www.vrt.be/vrtmax/livestream/video/vrt-canvas/',
'live_stream_id': 'vualto_canvas_geo',
'youtube': [
{'label': 'Canvas', 'url': 'https://www.youtube.com/user/CanvasTV'},
{'label': 'VRT Canvas', 'url': 'https://www.youtube.com/user/CanvasTV'},
{'label': 'Sporza', 'url': 'https://www.youtube.com/user/SporzaOfficial'},
{'label': 'Terzake', 'url': 'https://www.youtube.com/user/terzaketv'},
],
Expand Down
25 changes: 11 additions & 14 deletions plugin.video.vrt.nu/resources/lib/streamservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,17 @@ def _get_api_data(self, video):
elif video_id and not video_url:
api_data = ApiData(self._CLIENT, self._VUALTO_API_URL, video_id, '', True)
elif video_url:
model_url = video_url.strip('/') + '.model.json'
data_json = get_url_json(model_url)
if data_json:
# Get streamId
stream_id = None
for action in data_json.get('details').get('actions'):
if action.get('type') == 'watch-episode':
if action.get('videoType') == 'live':
is_live_stream = True
stream_id = action.get('streamId')
else:
is_live_stream = False
stream_id = action.get('episodePublicationId') + quote('$') + action.get('episodeVideoId')
api_data = ApiData(self._CLIENT, self._VUALTO_API_URL, stream_id, '', is_live_stream)
from api import get_stream_id_data
data_json = get_stream_id_data(video_url)
episode_data = data_json.get('data').get('page')
stream_id = ''
is_live_stream = False
if episode_data and episode_data.get('episode'):
stream_id = episode_data.get('episode').get('watchAction').get('streamId')
elif episode_data and episode_data.get('player'):
stream_id = episode_data.get('player').get('watchAction').get('streamId')
is_live_stream = True
api_data = ApiData(self._CLIENT, self._VUALTO_API_URL, stream_id, '', is_live_stream)
return api_data

def _get_stream_json(self, api_data, roaming=False):
Expand Down
Loading