Rebranding to GoPlay (#64)

* Support for rebranding to GoPlay
This commit is contained in:
Michaël Arnauts 2021-02-01 08:53:13 +01:00 committed by GitHub
parent 8a2129b894
commit e25ebfd8a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 347 additions and 355 deletions

3
.gitignore vendored
View File

@ -15,3 +15,6 @@ Thumbs.db
# Testing # Testing
tests/home/userdata/addon_data tests/home/userdata/addon_data
.env .env
Pipfile
Pipfile.lock

View File

@ -4,18 +4,18 @@
[![License: GPLv3](https://img.shields.io/badge/License-GPLv3-yellow.svg)](https://opensource.org/licenses/GPL-3.0) [![License: GPLv3](https://img.shields.io/badge/License-GPLv3-yellow.svg)](https://opensource.org/licenses/GPL-3.0)
[![Contributors](https://img.shields.io/github/contributors/add-ons/plugin.video.viervijfzes.svg)](https://github.com/add-ons/plugin.video.viervijfzes/graphs/contributors) [![Contributors](https://img.shields.io/github/contributors/add-ons/plugin.video.viervijfzes.svg)](https://github.com/add-ons/plugin.video.viervijfzes/graphs/contributors)
# VIER-VIJF-ZES Kodi add-on # GoPlay Kodi add-on
*plugin.video.viervijfzes* is een Kodi add-on om de video-on-demand content van [vier.be](https://www.vier.be/), [vijf.be](https://www.vijf.be/) en [zestv.be](https://www.zestv.be/) te bekijken. *plugin.video.viervijfzes* is een Kodi add-on om de video-on-demand content van [goplay.be](https://www.goplay.be/) te bekijken.
> Note: Je moet eerst een account aanmaken op één van bovenstaande websites. > Note: Je moet eerst een account aanmaken.
Meer informatie kan je vinden op de [Wiki pagina](https://github.com/add-ons/plugin.video.viervijfzes/wiki). Meer informatie kan je vinden op de [Wiki pagina](https://github.com/add-ons/plugin.video.viervijfzes/wiki).
## Features ## Features
De volgende features worden ondersteund: De volgende features worden ondersteund:
* Bekijk on-demand content van VIER, VIJF en ZES * Bekijk on-demand content van Play4, Play5 en Play6
* Programma's rechtstreeks afspelen vanuit de tv-gids * Programma's rechtstreeks afspelen vanuit de tv-gids
* Doorzoeken van alle programma's * Doorzoeken van alle programma's
* Afspelen van gerelateerde Youtube content * Afspelen van gerelateerde Youtube content
@ -34,4 +34,4 @@ De volgende features worden ondersteund:
## Disclaimer ## Disclaimer
Deze add-on wordt niet ondersteund door SBS Belgium, en wordt aangeboden 'as is', zonder enige garantie. Deze add-on wordt niet ondersteund door SBS Belgium, en wordt aangeboden 'as is', zonder enige garantie.
De logo's van VIER, VIJF en ZES zijn eigendom van SBS België. De logo's van GoPlay, Play4, Play5 en Play6 zijn eigendom van SBS België.

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.viervijfzes" name="VIER-VIJF-ZES" version="0.3.1" provider-name="Michaël Arnauts"> <addon id="plugin.video.viervijfzes" name="GoPlay" version="0.3.1" provider-name="Michaël Arnauts">
<requires> <requires>
<import addon="xbmc.python" version="2.26.0"/> <import addon="xbmc.python" version="2.26.0"/>
<import addon="script.module.dateutil" version="2.6.0"/> <import addon="script.module.dateutil" version="2.6.0"/>
@ -14,12 +14,12 @@
</extension> </extension>
<extension point="xbmc.service" library="service_entry.py"/> <extension point="xbmc.service" library="service_entry.py"/>
<extension point="xbmc.addon.metadata"> <extension point="xbmc.addon.metadata">
<summary lang="nl_NL">Bekijk programma's van VIER, VIJF en ZES.</summary> <summary lang="nl_NL">Bekijk programma's van Play4, Play5 en Play6.</summary>
<description lang="nl_NL">Deze add-on geeft toegang tot de programma's die aangeboden worden op de websites van VIER, VIJF en ZES.</description> <description lang="nl_NL">Deze add-on geeft toegang tot de programma's die aangeboden worden op de websites van Play4, Play5 en Play6.</description>
<disclaimer lang="nl_NL">Deze add-on wordt niet ondersteund door SBS België, en wordt aangeboden 'as is', zonder enige garantie. De logo's van VIER, VIJF en ZES zijn eigendom van SBS België.</disclaimer> <disclaimer lang="nl_NL">Deze add-on wordt niet ondersteund door SBS België, en wordt aangeboden 'as is', zonder enige garantie. De logo's van Play4, Play5 en Play6 zijn eigendom van SBS België.</disclaimer>
<summary lang="en_GB">Watch content from VIER, VIJF and ZES.</summary> <summary lang="en_GB">Watch content from Play4, Play5 and Play6.</summary>
<description lang="en_GB">This add-on gives access to video-on-demand content available on the websites of VIER, VIJF and ZES.</description> <description lang="en_GB">This add-on gives access to video-on-demand content available on the websites of Play4, Play5 and Play6.</description>
<disclaimer lang="en_GB">This add-on is not officially commissioned/supported by SBS Belgium and is provided 'as is' without any warranty of any kind. The VIER, VIJF and ZES logos are property of SBS Belgium.</disclaimer> <disclaimer lang="en_GB">This add-on is not officially commissioned/supported by SBS Belgium and is provided 'as is' without any warranty of any kind. The Play4, Play5 and Play6 logos are property of SBS Belgium.</disclaimer>
<platform>all</platform> <platform>all</platform>
<license>GPL-3.0-only</license> <license>GPL-3.0-only</license>
<news>v0.3.1 (2020-11-28) <news>v0.3.1 (2020-11-28)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -35,18 +35,18 @@ def show_channel_menu(channel):
Channels().show_channel_menu(channel) Channels().show_channel_menu(channel)
@routing.route('/channels/<channel>/categories') # @routing.route('/channels/<channel>/categories')
def show_channel_categories(channel): # def show_channel_categories(channel):
""" Shows TV Channel categories """ # """ Shows TV Channel categories """
from resources.lib.modules.channels import Channels # from resources.lib.modules.channels import Channels
Channels().show_channel_categories(channel) # Channels().show_channel_categories(channel)
@routing.route('/channels/<channel>/categories/<category>') # @routing.route('/channels/<channel>/categories/<category>')
def show_channel_category(channel, category): # def show_channel_category(channel, category):
""" Shows TV Channel categories """ # """ Shows TV Channel categories """
from resources.lib.modules.channels import Channels # from resources.lib.modules.channels import Channels
Channels().show_channel_category(channel, category) # Channels().show_channel_category(channel, category)
@routing.route('/channels/<channel>/tvguide') @routing.route('/channels/<channel>/tvguide')
@ -63,6 +63,13 @@ def show_channel_tvguide_detail(channel=None, date=None):
TvGuide().show_detail(channel, date) TvGuide().show_detail(channel, date)
@routing.route('/channels/<channel>/catalog')
def show_channel_catalog(channel):
""" Show the catalog of a channel """
from resources.lib.modules.catalog import Catalog
Catalog().show_catalog_channel(channel)
@routing.route('/catalog') @routing.route('/catalog')
def show_catalog(): def show_catalog():
""" Show the catalog """ """ Show the catalog """
@ -70,32 +77,25 @@ def show_catalog():
Catalog().show_catalog() Catalog().show_catalog()
@routing.route('/catalog/<channel>') @routing.route('/catalog/<program>')
def show_channel_catalog(channel): def show_catalog_program(program):
""" Show a category in the catalog """
from resources.lib.modules.catalog import Catalog
Catalog().show_catalog_channel(channel)
@routing.route('/catalog/<channel>/<program>')
def show_catalog_program(channel, program):
""" Show a program from the catalog """ """ Show a program from the catalog """
from resources.lib.modules.catalog import Catalog from resources.lib.modules.catalog import Catalog
Catalog().show_program(channel, program) Catalog().show_program(program)
@routing.route('/catalog/<channel>/<program>/clips') @routing.route('/catalog/<program>/clips')
def show_catalog_program_clips(channel, program): def show_catalog_program_clips(program):
""" Show the clips from a program """ """ Show the clips from a program """
from resources.lib.modules.catalog import Catalog from resources.lib.modules.catalog import Catalog
Catalog().show_program_clips(channel, program) Catalog().show_program_clips(program)
@routing.route('/catalog/<channel>/<program>/season/<season>') @routing.route('/catalog/<program>/season/<season>')
def show_catalog_program_season(channel, program, season): def show_catalog_program_season(program, season):
""" Show a season from a program """ """ Show a season from a program """
from resources.lib.modules.catalog import Catalog from resources.lib.modules.catalog import Catalog
Catalog().show_program_season(channel, program, season) Catalog().show_program_season(program, season)
@routing.route('/search') @routing.route('/search')
@ -127,8 +127,8 @@ def play_catalog(uuid):
Player().play(uuid) Player().play(uuid)
@routing.route('/play/page/<channel>/<page>') @routing.route('/play/page/<page>')
def play_from_page(channel, page): def play_from_page(page):
""" Play the requested item """ """ Play the requested item """
try: # Python 3 try: # Python 3
from urllib.parse import unquote from urllib.parse import unquote
@ -136,7 +136,7 @@ def play_from_page(channel, page):
from urllib import unquote from urllib import unquote
from resources.lib.modules.player import Player from resources.lib.modules.player import Player
Player().play_from_page(channel, unquote(page)) Player().play_from_page(unquote(page))
@routing.route('/metadata/update') @routing.route('/metadata/update')

View File

@ -8,7 +8,6 @@ import logging
from resources.lib import kodiutils from resources.lib import kodiutils
from resources.lib.kodiutils import TitleItem from resources.lib.kodiutils import TitleItem
from resources.lib.modules.menu import Menu from resources.lib.modules.menu import Menu
from resources.lib.viervijfzes import CHANNELS
from resources.lib.viervijfzes.auth import AuthApi from resources.lib.viervijfzes.auth import AuthApi
from resources.lib.viervijfzes.content import CACHE_PREVENT, ContentApi, UnavailableException from resources.lib.viervijfzes.content import CACHE_PREVENT, ContentApi, UnavailableException
@ -26,9 +25,7 @@ class Catalog:
def show_catalog(self): def show_catalog(self):
""" Show all the programs of all channels """ """ Show all the programs of all channels """
try: try:
items = [] items = self._api.get_programs()
for channel in list(CHANNELS):
items.extend(self._api.get_programs(channel))
except Exception as ex: except Exception as ex:
kodiutils.notification(message=str(ex)) kodiutils.notification(message=str(ex))
raise raise
@ -57,13 +54,12 @@ class Catalog:
# Used for A-Z listing or when movies and episodes are mixed. # Used for A-Z listing or when movies and episodes are mixed.
kodiutils.show_listing(listing, 30003, content='tvshows', sort='title') kodiutils.show_listing(listing, 30003, content='tvshows', sort='title')
def show_program(self, channel, program_id): def show_program(self, program_id):
""" Show a program from the catalog """ Show a program from the catalog
:type channel: str
:type program_id: str :type program_id: str
""" """
try: try:
program = self._api.get_program(channel, program_id, extract_clips=True, cache=CACHE_PREVENT) # Use CACHE_PREVENT since we want fresh data program = self._api.get_program(program_id, extract_clips=True, cache=CACHE_PREVENT) # Use CACHE_PREVENT since we want fresh data
except UnavailableException: except UnavailableException:
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue. kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
kodiutils.end_of_directory() kodiutils.end_of_directory()
@ -76,11 +72,9 @@ class Catalog:
# Go directly to the season when we have only one season and no clips # Go directly to the season when we have only one season and no clips
if not program.clips and len(program.seasons) == 1: if not program.clips and len(program.seasons) == 1:
self.show_program_season(channel, program_id, list(program.seasons.values())[0].uuid) self.show_program_season(program_id, list(program.seasons.values())[0].uuid)
return return
studio = CHANNELS.get(program.channel, {}).get('studio_icon')
listing = [] listing = []
# Add an '* All seasons' entry when configured in Kodi # Add an '* All seasons' entry when configured in Kodi
@ -88,7 +82,7 @@ class Catalog:
listing.append( listing.append(
TitleItem( TitleItem(
title='* %s' % kodiutils.localize(30204), # * All seasons title='* %s' % kodiutils.localize(30204), # * All seasons
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season='-1'), path=kodiutils.url_for('show_catalog_program_season', program=program_id, season='-1'),
art_dict={ art_dict={
'fanart': program.background, 'fanart': program.background,
}, },
@ -97,7 +91,6 @@ class Catalog:
'title': kodiutils.localize(30204), # All seasons 'title': kodiutils.localize(30204), # All seasons
'plot': program.description, 'plot': program.description,
'set': program.title, 'set': program.title,
'studio': studio,
} }
) )
) )
@ -107,7 +100,7 @@ class Catalog:
listing.append( listing.append(
TitleItem( TitleItem(
title=season.title, # kodiutils.localize(30205, season=season.number), # Season {season} title=season.title, # kodiutils.localize(30205, season=season.number), # Season {season}
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=season.uuid), path=kodiutils.url_for('show_catalog_program_season', program=program_id, season=season.uuid),
art_dict={ art_dict={
'fanart': program.background, 'fanart': program.background,
}, },
@ -116,7 +109,6 @@ class Catalog:
'title': kodiutils.localize(30205, season=season.number), # Season {season} 'title': kodiutils.localize(30205, season=season.number), # Season {season}
'plot': season.description, 'plot': season.description,
'set': program.title, 'set': program.title,
'studio': studio,
} }
) )
) )
@ -126,7 +118,7 @@ class Catalog:
listing.append( listing.append(
TitleItem( TitleItem(
title=kodiutils.localize(30059, program=program.title), # Clips for {program} title=kodiutils.localize(30059, program=program.title), # Clips for {program}
path=kodiutils.url_for('show_catalog_program_clips', channel=channel, program=program_id), path=kodiutils.url_for('show_catalog_program_clips', program=program_id),
art_dict={ art_dict={
'fanart': program.background, 'fanart': program.background,
}, },
@ -135,7 +127,6 @@ class Catalog:
'title': kodiutils.localize(30059, program=program.title), # Clips for {program} 'title': kodiutils.localize(30059, program=program.title), # Clips for {program}
'plot': kodiutils.localize(30060, program=program.title), # Watch short clips of {program} 'plot': kodiutils.localize(30060, program=program.title), # Watch short clips of {program}
'set': program.title, 'set': program.title,
'studio': studio,
} }
) )
) )
@ -143,14 +134,13 @@ class Catalog:
# Sort by label. Some programs return seasons unordered. # Sort by label. Some programs return seasons unordered.
kodiutils.show_listing(listing, 30003, content='tvshows') kodiutils.show_listing(listing, 30003, content='tvshows')
def show_program_season(self, channel, program_id, season_uuid): def show_program_season(self, program_id, season_uuid):
""" Show the episodes of a program from the catalog """ Show the episodes of a program from the catalog
:type channel: str
:type program_id: str :type program_id: str
:type season_uuid: str :type season_uuid: str
""" """
try: try:
program = self._api.get_program(channel, program_id) program = self._api.get_program(program_id)
except UnavailableException: except UnavailableException:
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue. kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
kodiutils.end_of_directory() kodiutils.end_of_directory()
@ -168,14 +158,13 @@ class Catalog:
# Sort by episode number by default. Takes seasons into account. # Sort by episode number by default. Takes seasons into account.
kodiutils.show_listing(listing, 30003, content='episodes', sort=['episode', 'duration']) kodiutils.show_listing(listing, 30003, content='episodes', sort=['episode', 'duration'])
def show_program_clips(self, channel, program_id): def show_program_clips(self, program_id):
""" Show the clips of a program from the catalog """ Show the clips of a program from the catalog
:type channel: str
:type program_id: str :type program_id: str
""" """
try: try:
# We need to query the backend, since we don't cache clips. # We need to query the backend, since we don't cache clips.
program = self._api.get_program(channel, program_id, extract_clips=True, cache=CACHE_PREVENT) program = self._api.get_program(program_id, extract_clips=True, cache=CACHE_PREVENT)
except UnavailableException: except UnavailableException:
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue. kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
kodiutils.end_of_directory() kodiutils.end_of_directory()

View File

@ -7,10 +7,9 @@ import logging
from resources.lib import kodiutils from resources.lib import kodiutils
from resources.lib.kodiutils import TitleItem from resources.lib.kodiutils import TitleItem
from resources.lib.modules.menu import Menu
from resources.lib.viervijfzes import CHANNELS, STREAM_DICT from resources.lib.viervijfzes import CHANNELS, STREAM_DICT
from resources.lib.viervijfzes.auth import AuthApi from resources.lib.viervijfzes.auth import AuthApi
from resources.lib.viervijfzes.content import CACHE_AUTO, CACHE_ONLY, ContentApi from resources.lib.viervijfzes.content import ContentApi
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -55,7 +54,6 @@ class Channels:
'plot': None, 'plot': None,
'playcount': 0, 'playcount': 0,
'mediatype': 'video', 'mediatype': 'video',
'studio': channel.get('studio_icon'),
}, },
stream_dict=STREAM_DICT, stream_dict=STREAM_DICT,
context_menu=context_menu context_menu=context_menu
@ -74,18 +72,24 @@ class Channels:
# Lookup the high resolution logo based on the channel name # Lookup the high resolution logo based on the channel name
fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel_info.get('background')) fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel_info.get('background'))
listing = [ listing = []
TitleItem(
title=kodiutils.localize(30053, channel=channel_info.get('name')), # TV Guide for {channel} if channel_info.get('epg_id'):
path=kodiutils.url_for('show_channel_tvguide', channel=channel), listing.append(
art_dict={ TitleItem(
'icon': 'DefaultAddonTvInfo.png', title=kodiutils.localize(30053, channel=channel_info.get('name')), # TV Guide for {channel}
'fanart': fanart, path=kodiutils.url_for('show_channel_tvguide', channel=channel),
}, art_dict={
info_dict={ 'icon': 'DefaultAddonTvInfo.png',
'plot': kodiutils.localize(30054, channel=channel_info.get('name')), # Browse the TV Guide for {channel} 'fanart': fanart,
} },
), info_dict={
'plot': kodiutils.localize(30054, channel=channel_info.get('name')), # Browse the TV Guide for {channel}
}
)
)
listing.append(
TitleItem( TitleItem(
title=kodiutils.localize(30055, channel=channel_info.get('name')), # Catalog for {channel} title=kodiutils.localize(30055, channel=channel_info.get('name')), # Catalog for {channel}
path=kodiutils.url_for('show_channel_catalog', channel=channel), path=kodiutils.url_for('show_channel_catalog', channel=channel),
@ -96,19 +100,22 @@ class Channels:
info_dict={ info_dict={
'plot': kodiutils.localize(30056, channel=channel_info.get('name')), # Browse the Catalog for {channel} 'plot': kodiutils.localize(30056, channel=channel_info.get('name')), # Browse the Catalog for {channel}
} }
), )
TitleItem( )
title=kodiutils.localize(30057, channel=channel_info.get('name')), # Categories for {channel}
path=kodiutils.url_for('show_channel_categories', channel=channel), # listing.append(
art_dict={ # TitleItem(
'icon': 'DefaultGenre.png', # title=kodiutils.localize(30057, channel=channel_info.get('name')), # Categories for {channel}
'fanart': fanart, # path=kodiutils.url_for('show_channel_categories', channel=channel),
}, # art_dict={
info_dict={ # 'icon': 'DefaultGenre.png',
'plot': kodiutils.localize(30058, channel=channel_info.get('name')), # Browse the Categories for {channel} # 'fanart': fanart,
} # },
), # info_dict={
] # 'plot': kodiutils.localize(30058, channel=channel_info.get('name')), # Browse the Categories for {channel}
# }
# )
# )
# Add YouTube channels # Add YouTube channels
if kodiutils.get_cond_visibility('System.HasAddon(plugin.video.youtube)') != 0: if kodiutils.get_cond_visibility('System.HasAddon(plugin.video.youtube)') != 0:
@ -125,57 +132,57 @@ class Channels:
kodiutils.show_listing(listing, 30007, sort=['unsorted']) kodiutils.show_listing(listing, 30007, sort=['unsorted'])
def show_channel_categories(self, channel): # def show_channel_categories(self, channel):
""" Shows the categories of a channel # """ Shows the categories of a channel
:type channel: str # :type channel: str
""" # """
categories = self._api.get_categories(channel) # categories = self._api.get_categories(channel)
#
# listing = [
# TitleItem(
# title=category.title,
# path=kodiutils.url_for('show_channel_category', channel=category.channel, category=category.uuid),
# art_dict={
# 'icon': 'DefaultGenre.png',
# },
# ) for category in categories
# ]
#
# kodiutils.show_listing(listing, 30007, sort=['unsorted'])
listing = [ # def show_channel_category(self, channel, category_id):
TitleItem( # """ Shows a selected category of a channel
title=category.title, # :type channel: str
path=kodiutils.url_for('show_channel_category', channel=category.channel, category=category.uuid), # :type category_id: str
art_dict={ # """
'icon': 'DefaultGenre.png', # categories = self._api.get_categories(channel)
}, #
) for category in categories # # Extract selected category
] # category = next(category for category in categories if category.uuid == category_id)
# if not category:
kodiutils.show_listing(listing, 30007, sort=['unsorted']) # raise Exception('Unknown category')
#
def show_channel_category(self, channel, category_id): # # Add programs
""" Shows a selected category of a channel # listing_programs = []
:type channel: str # for item in category.programs:
:type category_id: str # program = self._api.get_program(item.path, CACHE_ONLY) # Get program details, but from cache only
""" #
categories = self._api.get_categories(channel) # if program:
# listing_programs.append(Menu.generate_titleitem(program))
# Extract selected category # else:
category = next(category for category in categories if category.uuid == category_id) # listing_programs.append(Menu.generate_titleitem(item))
if not category: #
raise Exception('Unknown category') # # Add episodes
# listing_episodes = []
# Add programs # for item in category.episodes:
listing_programs = [] # # We don't have the Program Name without making a request to the page, so we use CACHE_AUTO instead of CACHE_ONLY.
for item in category.programs: # # This will make a request for each item in this view (about 12 items), but it goes quite fast.
program = self._api.get_program(channel, item.path, CACHE_ONLY) # Get program details, but from cache only # # Results are cached, so this will only happen once.
# episode = self._api.get_episode(item.path, CACHE_AUTO)
if program: #
listing_programs.append(Menu.generate_titleitem(program)) # if episode:
else: # listing_episodes.append(Menu.generate_titleitem(episode))
listing_programs.append(Menu.generate_titleitem(item)) # else:
# listing_episodes.append(Menu.generate_titleitem(item))
# Add episodes #
listing_episodes = [] # kodiutils.show_listing(listing_programs + listing_episodes, 30007, content='tvshows', sort=['unsorted'])
for item in category.episodes:
# We don't have the Program Name without making a request to the page, so we use CACHE_AUTO instead of CACHE_ONLY.
# This will make a request for each item in this view (about 12 items), but it goes quite fast.
# Results are cached, so this will only happen once.
episode = self._api.get_episode(channel, item.path, CACHE_AUTO)
if episode:
listing_episodes.append(Menu.generate_titleitem(episode))
else:
listing_episodes.append(Menu.generate_titleitem(item))
kodiutils.show_listing(listing_programs + listing_episodes, 30007, content='tvshows', sort=['unsorted'])

View File

@ -41,17 +41,16 @@ class IPTVManager:
"""Return JSON-STREAMS formatted information to IPTV Manager""" """Return JSON-STREAMS formatted information to IPTV Manager"""
streams = [] streams = []
for key, channel in CHANNELS.items(): for key, channel in CHANNELS.items():
item = dict( if channel.get('iptv_id'):
id=channel.get('iptv_id'), streams.append(dict(
name=channel.get('name'), id=channel.get('iptv_id'),
logo='special://home/addons/{addon}/resources/logos/{logo}'.format(addon=kodiutils.addon_id(), name=channel.get('name'),
logo=channel.get('logo')), logo='special://home/addons/{addon}/resources/logos/{logo}'.format(addon=kodiutils.addon_id(),
preset=channel.get('iptv_preset'), logo=channel.get('logo')),
stream='plugin://plugin.video.viervijfzes/play/live/{channel}'.format(channel=key), preset=channel.get('iptv_preset'),
vod='plugin://plugin.video.viervijfzes/play/epg/{channel}/{{date}}'.format(channel=key) stream='plugin://plugin.video.viervijfzes/play/live/{channel}'.format(channel=key),
) vod='plugin://plugin.video.viervijfzes/play/epg/{channel}/{{date}}'.format(channel=key)
))
streams.append(item)
return dict(version=1, streams=streams) return dict(version=1, streams=streams)
@ -69,25 +68,26 @@ class IPTVManager:
for key, channel in CHANNELS.items(): for key, channel in CHANNELS.items():
iptv_id = channel.get('iptv_id') iptv_id = channel.get('iptv_id')
results[iptv_id] = [] if channel.get('iptv_id'):
for date in ['yesterday', 'today', 'tomorrow']: results[iptv_id] = []
epg = epg_api.get_epg(key, date) for date in ['yesterday', 'today', 'tomorrow']:
epg = epg_api.get_epg(key, date)
results[iptv_id].extend([ results[iptv_id].extend([
dict( dict(
start=program.start.isoformat(), start=program.start.isoformat(),
stop=(program.start + timedelta(seconds=program.duration)).isoformat(), stop=(program.start + timedelta(seconds=program.duration)).isoformat(),
title=program.program_title, title=program.program_title,
subtitle=program.episode_title, subtitle=program.episode_title,
description=program.description, description=program.description,
episode='S%sE%s' % (program.season, program.number) if program.season and program.number else None, episode='S%sE%s' % (program.season, program.number) if program.season and program.number else None,
genre=program.genre, genre=program.genre,
genre_id=program.genre_id, genre_id=program.genre_id,
image=program.cover, image=program.cover,
stream=kodiutils.url_for('play_from_page', stream=kodiutils.url_for('play_from_page',
channel=key, channel=key,
page=quote(program.video_url, safe='')) if program.video_url else None) page=quote(program.video_url, safe='')) if program.video_url else None)
for program in epg if program.duration for program in epg if program.duration
]) ])
return dict(version=1, epg=results) return dict(version=1, epg=results)

View File

@ -5,7 +5,7 @@ from __future__ import absolute_import, division, unicode_literals
from resources.lib import kodiutils from resources.lib import kodiutils
from resources.lib.kodiutils import TitleItem from resources.lib.kodiutils import TitleItem
from resources.lib.viervijfzes import CHANNELS, STREAM_DICT from resources.lib.viervijfzes import STREAM_DICT
from resources.lib.viervijfzes.content import Episode, Program from resources.lib.viervijfzes.content import Episode, Program
@ -70,7 +70,6 @@ class Menu:
info_dict = { info_dict = {
'title': item.title, 'title': item.title,
'plot': item.description, 'plot': item.description,
'studio': CHANNELS.get(item.channel, {}).get('studio_icon'),
'aired': item.aired.strftime('%Y-%m-%d') if item.aired else None, 'aired': item.aired.strftime('%Y-%m-%d') if item.aired else None,
} }
prop_dict = {} prop_dict = {}

View File

@ -35,13 +35,12 @@ class Player:
kodiutils.ok_dialog(message=kodiutils.localize(30718, channel=channel_name.get('name'))) # There is no live stream available for {channel}. kodiutils.ok_dialog(message=kodiutils.localize(30718, channel=channel_name.get('name'))) # There is no live stream available for {channel}.
kodiutils.end_of_directory() kodiutils.end_of_directory()
def play_from_page(self, channel, path): def play_from_page(self, path):
""" Play the requested item. """ Play the requested item.
:type channel: string
:type path: string :type path: string
""" """
# Get episode information # Get episode information
episode = self._api.get_episode(channel, path) episode = self._api.get_episode(path)
resolved_stream = None resolved_stream = None
if episode is None: if episode is None:

View File

@ -181,4 +181,4 @@ class TvGuide:
kodiutils.end_of_directory() kodiutils.end_of_directory()
return return
Player().play_from_page(channel, broadcast.video_url) Player().play_from_page(broadcast.video_url)

View File

@ -1,50 +1,70 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" SBS API """ """ GoPlay API """
from __future__ import absolute_import, division, unicode_literals from __future__ import absolute_import, division, unicode_literals
from collections import OrderedDict from collections import OrderedDict
CHANNELS = OrderedDict([ CHANNELS = OrderedDict([
('vier', dict( ('Play4', dict(
name='VIER', name='Play4',
url='https://www.vier.be', epg_id='vier',
logo='vier.png', logo='play4.png',
background='vier-background.jpg', background='play4-background.png',
studio_icon='vier',
iptv_preset=4, iptv_preset=4,
iptv_id='vier.be', iptv_id='play4.be',
youtube=[ youtube=[
dict( dict(
label='VIER / VIJF', label='GoPlay',
logo='vier.png', logo='goplay.png',
path='plugin://plugin.video.youtube/user/viertv/', path='plugin://plugin.video.youtube/user/viertv/',
), ),
], ],
)), )),
('vijf', dict( ('Play5', dict(
name='VIJF', name='Play5',
url='https://www.vijf.be', epg_id='vijf',
logo='vijf.png', logo='play5.png',
background='vijf-background.jpg', background='play5-background.png',
studio_icon='vijf',
iptv_preset=5, iptv_preset=5,
iptv_id='vijf.be', iptv_id='play5.be',
youtube=[ youtube=[
dict( dict(
label='VIER / VIJF', label='GoPlay',
logo='vijf.png', logo='goplay.png',
path='plugin://plugin.video.youtube/user/viertv/', path='plugin://plugin.video.youtube/user/viertv/',
), ),
], ],
)), )),
('zes', dict( ('Play6', dict(
name='ZES', name='Play6',
url='https://www.zestv.be', epg_id='zes',
logo='zes.png', logo='play6.png',
background='zes-background.jpg', background='play6-background.png',
studio_icon='zes',
iptv_preset=6, iptv_preset=6,
iptv_id='zes.be', iptv_id='play6.be',
youtube=[
dict(
label='GoPlay',
logo='goplay.png',
path='plugin://plugin.video.youtube/user/viertv/',
),
],
)),
# ('Play7', dict(
# name='Play7',
# epg_id='zeven',
# url='https://www.goplay.be',
# logo='play7.png',
# background='play7-background.png',
# iptv_preset=7,
# iptv_id='play7.be',
# youtube=[],
# )),
('GoPlay', dict(
name='Go Play',
url='https://www.goplay.be',
logo='goplay.png',
background='goplay-background.png',
youtube=[], youtube=[],
)) ))
]) ])

View File

@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__)
class AuthApi: class AuthApi:
""" VIER/VIJF/ZES Authentication API """ """ GoPlay Authentication API """
COGNITO_REGION = 'eu-west-1' COGNITO_REGION = 'eu-west-1'
COGNITO_POOL_ID = 'eu-west-1_dViSsKM5Y' COGNITO_POOL_ID = 'eu-west-1_dViSsKM5Y'
COGNITO_CLIENT_ID = '6s1h851s8uplco5h6mqh1jac8m' COGNITO_CLIENT_ID = '6s1h851s8uplco5h6mqh1jac8m'

View File

@ -13,7 +13,7 @@ from datetime import datetime
import requests import requests
from resources.lib.kodiutils import STREAM_DASH, STREAM_HLS from resources.lib.kodiutils import STREAM_DASH, STREAM_HLS
from resources.lib.viervijfzes import CHANNELS, ResolvedStream from resources.lib.viervijfzes import ResolvedStream
try: # Python 3 try: # Python 3
from html import unescape from html import unescape
@ -169,14 +169,10 @@ class Category:
class ContentApi: class ContentApi:
""" VIER/VIJF/ZES Content API""" """ GoPlay Content API"""
API_ENDPOINT = 'https://api.viervijfzes.be' SITE_URL = 'https://www.goplay.be'
API2_ENDPOINT = 'https://api2.viervijfzes.be' API_VIERVIJFZES = 'https://api.viervijfzes.be'
SITE_APIS = { API_GOPLAY = 'https://api.goplay.be'
'vier': 'https://www.vier.be/api',
'vijf': 'https://www.vijf.be/api',
'zes': 'https://www.zestv.be/api',
}
def __init__(self, auth=None, cache_path=None): def __init__(self, auth=None, cache_path=None):
""" Initialise object """ """ Initialise object """
@ -184,64 +180,53 @@ class ContentApi:
self._auth = auth self._auth = auth
self._cache_path = cache_path self._cache_path = cache_path
def get_programs(self, channel, cache=CACHE_AUTO): def get_programs(self, channel=None, cache=CACHE_AUTO):
""" Get a list of all programs of the specified channel. """ Get a list of all programs of the specified channel.
:type channel: str
:type cache: str :type cache: str
:rtype list[Program] :rtype list[Program]
""" """
if channel not in CHANNELS:
raise Exception('Unknown channel %s' % channel)
def update(): def update():
""" Fetch the program listing by scraping """ """ Fetch the program listing by scraping """
# Load webpage # Load webpage
raw_html = self._get_url(CHANNELS[channel]['url']) raw_html = self._get_url(self.SITE_URL + '/programmas')
# Parse programs # Parse programs
regex_programs = re.compile(r'<a class="program-overview__link" href="(?P<path>[^"]+)">\s+' regex_programs = re.compile(r'data-program="(?P<json>[^"]+)"', re.DOTALL)
r'<span class="program-overview__title">\s+(?P<title>[^<]+)</span>.*?'
r'</a>', re.DOTALL) data = [
data = { json.loads(unescape(item.group('json')))
item.group('path').lstrip('/'): unescape(item.group('title').strip())
for item in regex_programs.finditer(raw_html) for item in regex_programs.finditer(raw_html)
} ]
if not data: if not data:
raise Exception('No programs found for %s' % channel) raise Exception('No programs found')
return data return data
# Fetch listing from cache or update if needed # Fetch listing from cache or update if needed
data = self._handle_cache(key=['programs', channel], cache_mode=cache, update=update, ttl=30 * 5) data = self._handle_cache(key=['programs'], cache_mode=cache, update=update, ttl=30 * 5)
if not data: if not data:
return [] return []
programs = [] if channel:
for path in data: programs = [
title = data[path] self._parse_program_data(record) for record in data if record['pageInfo']['brand'] == channel
program = self.get_program(channel, path, cache=CACHE_ONLY) # Get program details, but from cache only ]
if program: else:
# Use program with metadata from cache programs = [
programs.append(program) self._parse_program_data(record) for record in data
else: ]
# Use program with the values that we've parsed from the page
programs.append(Program(channel=channel,
path=path,
title=title))
return programs return programs
def get_program(self, channel, path, extract_clips=False, cache=CACHE_AUTO): def get_program(self, path, extract_clips=False, cache=CACHE_AUTO):
""" Get a Program object from the specified page. """ Get a Program object from the specified page.
:type channel: str
:type path: str :type path: str
:type extract_clips: bool :type extract_clips: bool
:type cache: int :type cache: int
:rtype Program :rtype Program
""" """
if channel not in CHANNELS:
raise Exception('Unknown channel %s' % channel)
# We want to use the html to extract clips # We want to use the html to extract clips
# This is the worst hack, since Python 2.7 doesn't support nonlocal # This is the worst hack, since Python 2.7 doesn't support nonlocal
raw_html = [None] raw_html = [None]
@ -249,7 +234,7 @@ class ContentApi:
def update(): def update():
""" Fetch the program metadata by scraping """ """ Fetch the program metadata by scraping """
# Fetch webpage # Fetch webpage
page = self._get_url(CHANNELS[channel]['url'] + '/' + path) page = self._get_url(self.SITE_URL + '/' + path)
# Store a copy in the parent's raw_html var. # Store a copy in the parent's raw_html var.
raw_html[0] = page raw_html[0] = page
@ -262,7 +247,7 @@ class ContentApi:
return data return data
# Fetch listing from cache or update if needed # Fetch listing from cache or update if needed
data = self._handle_cache(key=['program', channel, path], cache_mode=cache, update=update) data = self._handle_cache(key=['program', path], cache_mode=cache, update=update)
if not data: if not data:
return None return None
@ -270,25 +255,22 @@ class ContentApi:
# Also extract clips if we did a real HTTP call # Also extract clips if we did a real HTTP call
if extract_clips and raw_html[0]: if extract_clips and raw_html[0]:
clips = self._extract_videos(raw_html[0], channel) clips = self._extract_videos(raw_html[0])
program.clips = clips program.clips = clips
return program return program
def get_episode(self, channel, path, cache=CACHE_AUTO): def get_episode(self, path, cache=CACHE_AUTO):
""" Get a Episode object from the specified page. """ Get a Episode object from the specified page.
:type channel: str
:type path: str :type path: str
:type cache: str :type cache: str
:rtype Episode :rtype Episode
""" """
if channel not in CHANNELS:
raise Exception('Unknown channel %s' % channel)
def update(): def update():
""" Fetch the program metadata by scraping """ """ Fetch the program metadata by scraping """
# Load webpage # Load webpage
page = self._get_url(CHANNELS[channel]['url'] + '/' + path) page = self._get_url(self.SITE_URL + '/' + path)
program_json = None program_json = None
episode_json = None episode_json = None
@ -299,7 +281,7 @@ class ContentApi:
result = regex_video_data.search(page) result = regex_video_data.search(page)
if result: if result:
video_id = json.loads(unescape(result.group(1)))['id'] video_id = json.loads(unescape(result.group(1)))['id']
video_json_data = self._get_url('%s/video/%s' % (self.SITE_APIS[channel], video_id)) video_json_data = self._get_url('%s/api/video/%s' % (self.SITE_URL, video_id))
video_json = json.loads(video_json_data) video_json = json.loads(video_json_data)
return dict(video=video_json) return dict(video=video_json)
@ -320,7 +302,7 @@ class ContentApi:
return dict(program=program_json, episode=episode_json) return dict(program=program_json, episode=episode_json)
# Fetch listing from cache or update if needed # Fetch listing from cache or update if needed
data = self._handle_cache(key=['episode', channel, path], cache_mode=cache, update=update) data = self._handle_cache(key=['episode', path], cache_mode=cache, update=update)
if not data: if not data:
return None return None
@ -344,7 +326,7 @@ class ContentApi:
:type uuid: str :type uuid: str
:rtype str :rtype str
""" """
response = self._get_url(self.API_ENDPOINT + '/content/%s' % uuid, authentication=True) response = self._get_url(self.API_VIERVIJFZES + '/content/%s' % uuid, authentication=True)
data = json.loads(response) data = json.loads(response)
if 'videoDash' in data: if 'videoDash' in data:
@ -353,7 +335,7 @@ class ContentApi:
drm_key = data['drmKey']['S'] drm_key = data['drmKey']['S']
_LOGGER.debug('Fetching Authentication XML with drm_key %s', drm_key) _LOGGER.debug('Fetching Authentication XML with drm_key %s', drm_key)
response_drm = self._get_url(self.API2_ENDPOINT + '/decode/%s' % drm_key, authentication=True) response_drm = self._get_url(self.API_GOPLAY + '/restricted/decode/%s' % drm_key, authentication=True)
data_drm = json.loads(response_drm) data_drm = json.loads(response_drm)
return ResolvedStream( return ResolvedStream(
@ -371,68 +353,64 @@ class ContentApi:
stream_type=STREAM_HLS, stream_type=STREAM_HLS,
) )
def get_categories(self, channel): # def get_categories(self):
""" Get a list of all categories of the specified channel. # """ Get a list of all categories.
:type channel: str # :rtype list[Category]
:rtype list[Category] # """
""" # # Load webpage
if channel not in CHANNELS: # raw_html = self._get_url(self.SITE_URL)
raise Exception('Unknown channel %s' % channel) #
# # Categories regexes
# regex_articles = re.compile(r'<article([^>]+)>(.*?)</article>', re.DOTALL)
# regex_submenu_id = re.compile(r'data-submenu-id="([^"]*)"') # splitted since the order might change
# regex_submenu_title = re.compile(r'data-submenu-title="([^"]*)"')
#
# categories = []
# for result in regex_articles.finditer(raw_html):
# article_info_html = result.group(1)
# article_html = result.group(2)
# category_title = regex_submenu_title.search(article_info_html).group(1)
# category_id = regex_submenu_id.search(article_info_html).group(1)
#
# # Skip empty categories or 'All programs'
# if not category_id or category_id == 'programmas':
# continue
#
# # Extract items
# programs = self._extract_programs(article_html, channel)
# episodes = self._extract_videos(article_html)
# categories.append(Category(uuid=category_id, channel=channel, title=category_title, programs=programs, episodes=episodes))
#
# return categories
# Load webpage # @staticmethod
raw_html = self._get_url(CHANNELS[channel]['url']) # def _extract_programs(html, channel):
# """ Extract Programs from HTML code """
# Categories regexes # # Item regexes
regex_articles = re.compile(r'<article([^>]+)>(.*?)</article>', re.DOTALL) # regex_item = re.compile(r'<a[^>]+?href="(?P<path>[^"]+)"[^>]+?>'
regex_submenu_id = re.compile(r'data-submenu-id="([^"]*)"') # splitted since the order might change # r'.*?<h3 class="poster-teaser__title"><span>(?P<title>[^<]*)</span></h3>.*?'
regex_submenu_title = re.compile(r'data-submenu-title="([^"]*)"') # r'</a>', re.DOTALL)
#
categories = [] # # Extract items
for result in regex_articles.finditer(raw_html): # programs = []
article_info_html = result.group(1) # for item in regex_item.finditer(html):
article_html = result.group(2) # path = item.group('path')
category_title = regex_submenu_title.search(article_info_html).group(1) # if path.startswith('/video'):
category_id = regex_submenu_id.search(article_info_html).group(1) # continue
#
# Skip empty categories or 'All programs' # title = unescape(item.group('title'))
if not category_id or category_id == 'programmas': #
continue # # Program
# programs.append(Program(
# Extract items # path=path.lstrip('/'),
programs = self._extract_programs(article_html, channel) # channel=channel,
episodes = self._extract_videos(article_html, channel) # title=title,
categories.append(Category(uuid=category_id, channel=channel, title=category_title, programs=programs, episodes=episodes)) # ))
#
return categories # return programs
@staticmethod @staticmethod
def _extract_programs(html, channel): def _extract_videos(html):
""" Extract Programs from HTML code """
# Item regexes
regex_item = re.compile(r'<a[^>]+?href="(?P<path>[^"]+)"[^>]+?>'
r'.*?<h3 class="poster-teaser__title"><span>(?P<title>[^<]*)</span></h3>.*?'
r'</a>', re.DOTALL)
# Extract items
programs = []
for item in regex_item.finditer(html):
path = item.group('path')
if path.startswith('/video'):
continue
title = unescape(item.group('title'))
# Program
programs.append(Program(
path=path.lstrip('/'),
channel=channel,
title=title,
))
return programs
@staticmethod
def _extract_videos(html, channel):
""" Extract videos from HTML code """ """ Extract videos from HTML code """
# Item regexes # Item regexes
regex_item = re.compile(r'<a[^>]+?href="(?P<path>[^"]+)"[^>]+?>.*?</a>', re.DOTALL) regex_item = re.compile(r'<a[^>]+?href="(?P<path>[^"]+)"[^>]+?>.*?</a>', re.DOTALL)
@ -490,7 +468,7 @@ class ContentApi:
# Episode # Episode
episodes.append(Episode( episodes.append(Episode(
path=path.lstrip('/'), path=path.lstrip('/'),
channel=channel, channel='', # TODO
title=title, title=title,
duration=episode_duration, duration=episode_duration,
uuid=episode_video_id, uuid=episode_video_id,
@ -511,7 +489,7 @@ class ContentApi:
program = Program( program = Program(
uuid=data['id'], uuid=data['id'],
path=data['link'].lstrip('/'), path=data['link'].lstrip('/'),
channel=data['pageInfo']['site'], channel=data['pageInfo']['brand'],
title=data['title'], title=data['title'],
description=data['description'], description=data['description'],
aired=datetime.fromtimestamp(data.get('pageInfo', {}).get('publishDate')), aired=datetime.fromtimestamp(data.get('pageInfo', {}).get('publishDate')),
@ -524,7 +502,7 @@ class ContentApi:
key: Season( key: Season(
uuid=playlist['id'], uuid=playlist['id'],
path=playlist['link'].lstrip('/'), path=playlist['link'].lstrip('/'),
channel=playlist['pageInfo']['site'], channel=playlist['pageInfo']['brand'],
title=playlist['title'], title=playlist['title'],
description=playlist['pageInfo']['description'], description=playlist['pageInfo']['description'],
number=playlist['episodes'][0]['seasonNumber'], # You did not see this number=playlist['episodes'][0]['seasonNumber'], # You did not see this

View File

@ -67,12 +67,12 @@ class EpgProgram:
class EpgApi: class EpgApi:
""" VIER/VIJF/ZES EPG API """ """ GoPlay EPG API """
EPG_ENDPOINTS = { EPG_ENDPOINTS = {
'vier': 'https://www.vier.be/api/epg/{date}', 'Play4': 'https://www.goplay.be/api/epg/vier/{date}',
'vijf': 'https://www.vijf.be/api/epg/{date}', 'Play5': 'https://www.goplay.be/api/epg/vijf/{date}',
'zes': 'https://www.zestv.be/api/epg/{date}', 'Play6': 'https://www.goplay.be/api/epg/zes/{date}'
} }
EPG_NO_BROADCAST = 'Geen uitzending' EPG_NO_BROADCAST = 'Geen uitzending'

View File

@ -14,7 +14,7 @@ _LOGGER = logging.getLogger(__name__)
class SearchApi: class SearchApi:
""" VIER/VIJF/ZES Search API """ """ GoPlay Search API """
API_ENDPOINT = 'https://api.viervijfzes.be/search' API_ENDPOINT = 'https://api.viervijfzes.be/search'
def __init__(self): def __init__(self):

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
resources/logos/goplay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
resources/logos/play4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
resources/logos/play5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
resources/logos/play6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -11,7 +11,7 @@ import unittest
import resources.lib.kodiutils as kodiutils import resources.lib.kodiutils as kodiutils
from resources.lib.viervijfzes import ResolvedStream from resources.lib.viervijfzes import ResolvedStream
from resources.lib.viervijfzes.auth import AuthApi from resources.lib.viervijfzes.auth import AuthApi
from resources.lib.viervijfzes.content import ContentApi, Program, Episode, Category, CACHE_PREVENT from resources.lib.viervijfzes.content import ContentApi, Program, Episode, CACHE_PREVENT
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -23,39 +23,36 @@ class TestApi(unittest.TestCase):
self._api = ContentApi(auth, cache_path=kodiutils.get_cache_path()) self._api = ContentApi(auth, cache_path=kodiutils.get_cache_path())
def test_programs(self): def test_programs(self):
for channel in ['vier', 'vijf', 'zes']: programs = self._api.get_programs()
programs = self._api.get_programs(channel) self.assertIsInstance(programs, list)
self.assertIsInstance(programs, list) self.assertIsInstance(programs[0], Program)
self.assertIsInstance(programs[0], Program)
def test_categories(self): # def test_categories(self):
for channel in ['vier', 'vijf', 'zes']: # categories = self._api.get_categories()
categories = self._api.get_categories(channel) # self.assertIsInstance(categories, list)
self.assertIsInstance(categories, list) # self.assertIsInstance(categories[0], Category)
if categories:
self.assertIsInstance(categories[0], Category)
def test_episodes(self): def test_episodes(self):
for channel, program in [('vier', 'auwch'), ('vijf', 'zo-man-zo-vrouw')]: for program in ['auwch', 'zo-man-zo-vrouw']:
program = self._api.get_program(channel, program, cache=CACHE_PREVENT) program = self._api.get_program(program, cache=CACHE_PREVENT)
self.assertIsInstance(program, Program) self.assertIsInstance(program, Program)
self.assertIsInstance(program.seasons, dict) self.assertIsInstance(program.seasons, dict)
self.assertIsInstance(program.episodes, list) self.assertIsInstance(program.episodes, list)
self.assertIsInstance(program.episodes[0], Episode) self.assertIsInstance(program.episodes[0], Episode)
def test_clips(self): def test_clips(self):
for channel, program in [('vier', 'gert-late-night')]: for program in ['gert-late-night']:
program = self._api.get_program(channel, program, extract_clips=True, cache=CACHE_PREVENT) program = self._api.get_program(program, extract_clips=True, cache=CACHE_PREVENT)
self.assertIsInstance(program.clips, list) self.assertIsInstance(program.clips, list)
self.assertIsInstance(program.clips[0], Episode) self.assertIsInstance(program.clips[0], Episode)
episode = self._api.get_episode(channel, program.clips[0].path, cache=CACHE_PREVENT) episode = self._api.get_episode(program.clips[0].path, cache=CACHE_PREVENT)
self.assertIsInstance(episode, Episode) self.assertIsInstance(episode, Episode)
@unittest.skipUnless(kodiutils.get_setting('username') and kodiutils.get_setting('password'), 'Skipping since we have no credentials.') @unittest.skipUnless(kodiutils.get_setting('username') and kodiutils.get_setting('password'), 'Skipping since we have no credentials.')
def test_get_stream(self): def test_get_stream(self):
program = self._api.get_program('vier', 'auwch') program = self._api.get_program('auwch')
self.assertIsInstance(program, Program) self.assertIsInstance(program, Program)
episode = program.episodes[0] episode = program.episodes[0]
@ -64,7 +61,7 @@ class TestApi(unittest.TestCase):
@unittest.skipUnless(kodiutils.get_setting('username') and kodiutils.get_setting('password'), 'Skipping since we have no credentials.') @unittest.skipUnless(kodiutils.get_setting('username') and kodiutils.get_setting('password'), 'Skipping since we have no credentials.')
def test_get_drm_stream(self): def test_get_drm_stream(self):
resolved_stream = self._api.get_stream_by_uuid('b56a41d9-5a6a-4ff0-b16a-56dc7b2e1f25') resolved_stream = self._api.get_stream_by_uuid('a545bb4f-0f4c-4588-92a2-5086041c0e08') # Hawaii Five-O 8x12
self.assertIsInstance(resolved_stream, ResolvedStream) self.assertIsInstance(resolved_stream, ResolvedStream)

View File

@ -22,17 +22,17 @@ class TestEpg(unittest.TestCase):
self._epg = EpgApi() self._epg = EpgApi()
def test_vier_today(self): def test_vier_today(self):
programs = self._epg.get_epg('vier', date.today().strftime('%Y-%m-%d')) programs = self._epg.get_epg('Play4', date.today().strftime('%Y-%m-%d'))
self.assertIsInstance(programs, list) self.assertIsInstance(programs, list)
self.assertIsInstance(programs[0], EpgProgram) self.assertIsInstance(programs[0], EpgProgram)
def test_vijf_today(self): def test_vijf_today(self):
programs = self._epg.get_epg('vijf', date.today().strftime('%Y-%m-%d')) programs = self._epg.get_epg('Play5', date.today().strftime('%Y-%m-%d'))
self.assertIsInstance(programs, list) self.assertIsInstance(programs, list)
self.assertIsInstance(programs[0], EpgProgram) self.assertIsInstance(programs[0], EpgProgram)
def test_zes_today(self): def test_zes_today(self):
programs = self._epg.get_epg('zes', date.today().strftime('%Y-%m-%d')) programs = self._epg.get_epg('Play6', date.today().strftime('%Y-%m-%d'))
self.assertIsInstance(programs, list) self.assertIsInstance(programs, list)
self.assertIsInstance(programs[0], EpgProgram) self.assertIsInstance(programs[0], EpgProgram)
@ -41,16 +41,16 @@ class TestEpg(unittest.TestCase):
self._epg.get_epg('vtm', date.today().strftime('%Y-%m-%d')) self._epg.get_epg('vtm', date.today().strftime('%Y-%m-%d'))
def test_vier_out_of_range(self): def test_vier_out_of_range(self):
programs = self._epg.get_epg('vier', '2020-01-01') programs = self._epg.get_epg('Play4', '2020-01-01')
self.assertEqual(programs, []) self.assertEqual(programs, [])
def test_play_video_from_epg(self): def test_play_video_from_epg(self):
epg_programs = self._epg.get_epg('vier', 'yesterday') epg_programs = self._epg.get_epg('Play4', 'yesterday')
epg_program = [program for program in epg_programs if program.video_url][0] epg_program = [program for program in epg_programs if program.video_url][0]
# Lookup the Episode data since we don't have an UUID # Lookup the Episode data since we don't have an UUID
api = ContentApi(cache_path=kodiutils.get_cache_path()) api = ContentApi(cache_path=kodiutils.get_cache_path())
episode = api.get_episode(epg_program.channel, epg_program.video_url) episode = api.get_episode(epg_program.video_url)
self.assertIsInstance(episode, Episode) self.assertIsInstance(episode, Episode)
# def test_map_epg_genre(self): # def test_map_epg_genre(self):

View File

@ -29,27 +29,27 @@ class TestRouting(unittest.TestCase):
def test_channels_menu(self): def test_channels_menu(self):
routing.run([routing.url_for(addon.show_channels), '0', '']) routing.run([routing.url_for(addon.show_channels), '0', ''])
routing.run([routing.url_for(addon.show_channel_menu, channel='vier'), '0', '']) routing.run([routing.url_for(addon.show_channel_menu, channel='Play4'), '0', ''])
def test_catalog_menu(self): def test_catalog_menu(self):
routing.run([routing.url_for(addon.show_catalog), '0', '']) routing.run([routing.url_for(addon.show_catalog), '0', ''])
def test_catalog_channel_menu(self): def test_catalog_channel_menu(self):
routing.run([routing.url_for(addon.show_channel_catalog, channel='vier'), '0', '']) routing.run([routing.url_for(addon.show_channel_catalog, channel='Play4'), '0', ''])
def test_catalog_program_menu(self): def test_catalog_program_menu(self):
routing.run([routing.url_for(addon.show_catalog_program, channel='vier', program='de-mol'), '0', '']) routing.run([routing.url_for(addon.show_catalog_program, channel='Play4', program='de-mol'), '0', ''])
def test_catalog_program_season_menu(self): def test_catalog_program_season_menu(self):
routing.run([routing.url_for(addon.show_catalog_program_season, channel='vier', program='de-mol', season=-1), '0', '']) routing.run([routing.url_for(addon.show_catalog_program_season, channel='Play4', program='de-mol', season=-1), '0', ''])
def test_search_menu(self): def test_search_menu(self):
routing.run([routing.url_for(addon.show_search), '0', '']) routing.run([routing.url_for(addon.show_search), '0', ''])
routing.run([routing.url_for(addon.show_search, query='de mol'), '0', '']) routing.run([routing.url_for(addon.show_search, query='de mol'), '0', ''])
def test_tvguide_menu(self): def test_tvguide_menu(self):
routing.run([routing.url_for(addon.show_channel_tvguide, channel='vier'), '0', '']) routing.run([routing.url_for(addon.show_channel_tvguide, channel='Play4'), '0', ''])
routing.run([routing.url_for(addon.show_channel_tvguide_detail, channel='vier', date='today'), '0', '']) routing.run([routing.url_for(addon.show_channel_tvguide_detail, channel='Play4', date='today'), '0', ''])
# def test_metadata_update(self): # def test_metadata_update(self):
# routing.run([routing.url_for(addon.metadata_update), '0', '']) # routing.run([routing.url_for(addon.metadata_update), '0', ''])