Merge remote-tracking branch 'mediaminister/live' into main

This commit is contained in:
Jeroen De Meerleer 2024-05-08 14:53:23 +02:00
commit 97d80f2115
Signed by: JeroenED
GPG Key ID: 28CCCB8F62BFADD6
36 changed files with 970 additions and 476 deletions

View File

@ -4,3 +4,11 @@ ADDON_PASSWORD=
KODI_HOME=tests/home
KODI_INTERACTIVE=0
KODI_STUB_VERBOSE=1
KODI_STUB_RPC_RESPONSES=tests/rpc
#HTTP_PROXY=
#HTTPS_PROXY=
GH_USERNAME=
GH_TOKEN=
EMAIL=

1
.gitattributes vendored
View File

@ -6,3 +6,4 @@ tests/ export-ignore
.pylintrc export-ignore
Makefile export-ignore
requirements.txt export-ignore
scripts/ export-ignore

View File

@ -11,10 +11,6 @@ jobs:
kodi-addon-checker:
name: Addon checker
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
kodi-version: [ leia, matrix ]
steps:
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
uses: actions/checkout@v2
@ -22,6 +18,5 @@ jobs:
- name: Run kodi-addon-checker
uses: xbmc/action-kodi-addon-checker@v1.2
with:
kodi-version: ${{ matrix.kodi-version }}
rewrite-for-matrix: ${{ matrix.kodi-version == 'matrix' }}
kodi-version: matrix
addon-id: ${{ github.event.repository.name }}

View File

@ -3,10 +3,10 @@ on:
# Run action when pushed to master, or for commits in a pull request.
push:
branches:
- master
- master
pull_request:
branches:
- master
- master
jobs:
tests:
name: Add-on testing
@ -14,24 +14,22 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
python-version: [ 2.7, 3.5, 3.6, 3.7, 3.8, 3.9 ]
os: [ ubuntu-latest, windows-latest ]
python-version: ["3.8", "3.9", "3.10"]
include:
# Kodi Leia on Windows uses a bundled Python 2.7.
- os: windows-latest
python-version: 2.7
# Kodi Matrix on Windows uses a bundled Python 3.8, but we test 3.9 also to be sure.
- os: windows-latest
python-version: 3.8
- os: windows-latest
python-version: 3.9
# End-of-life Python versions are not available anymore with ubuntu-latest
- os: ubuntu-20.04
python-version: "3.5"
- os: ubuntu-20.04
python-version: "3.6"
- os: ubuntu-20.04
python-version: "3.7"
steps:
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
@ -54,14 +52,14 @@ jobs:
KODI_INTERACTIVE: 0
KODI_STUB_RPC_RESPONSES: ${{ github.workspace }}/tests/rpc
HTTP_PROXY: ${{ secrets.HTTP_PROXY }}
run: pytest -v --cov=./ --cov-report=xml tests
run: pytest -x -v --cov=./ --cov-report=xml tests
- name: Upload code coverage to CodeCov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v3
continue-on-error: true
env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}
with:
flags: unittests
env_vars: OS,PYTHON
env_vars: OS,PYTHON

View File

@ -6,22 +6,13 @@ on:
jobs:
build:
name: Release plugin.video.viervijfzes
if: startsWith(github.ref, 'refs/tags/') # prevent from running if it's not a tag
runs-on: ubuntu-latest
steps:
- name: Checkout code
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
uses: actions/checkout@v2
- name: Build zip files
id: build
run: |
sudo apt-get install libxml2-utils
make multizip release=1
echo ::set-output name=leia-filename::$(cd ..;ls plugin.video.viervijfzes*.zip | grep -v '+matrix.' | head -1)
echo ::set-output name=matrix-filename::$(cd ..;ls plugin.video.viervijfzes*+matrix.*.zip | head -1)
- name: Get body
id: get-body
- name: Get changelog
id: get-changelog
run: |
description=$(sed '1,6d;/^## /,$d' CHANGELOG.md)
echo $description
@ -30,47 +21,14 @@ jobs:
description="${description//$'\r'/'%0D'}"
echo ::set-output name=body::$description
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Generate distribution zips
run: scripts/build.py
- name: Create Release on Github
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: ${{ steps.get-body.outputs.body }}
body: ${{ steps.get-changelog.outputs.body }}
draft: false
prerelease: false
- name: Upload Leia zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_name: ${{ steps.build.outputs.leia-filename }}
asset_path: ../${{ steps.build.outputs.leia-filename }}
asset_content_type: application/zip
- name: Upload Matrix zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_name: ${{ steps.build.outputs.matrix-filename }}
asset_path: ../${{ steps.build.outputs.matrix-filename }}
asset_content_type: application/zip
- name: Generate distribution zip and submit to official kodi repository
id: kodi-addon-submitter
uses: xbmc/action-kodi-addon-submitter@v1.2
with:
kodi-repository: repo-plugins
addon-id: plugin.video.viervijfzes
kodi-version: leia
kodi-matrix: true
env:
GH_USERNAME: ${{ secrets.GH_USERNAME }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
EMAIL: ${{ secrets.EMAIL }}
files: "dist/*.zip"
token: ${{ secrets.GH_TOKEN }}

2
.gitignore vendored
View File

@ -18,3 +18,5 @@ tests/home/userdata/addon_data
Pipfile
Pipfile.lock
dist/

View File

@ -18,6 +18,8 @@ disable=
use-maxsplit-arg,
consider-using-from-import,
unspecified-encoding,
broad-exception-raised,
super-with-arguments, # Python 2.7 compatibility
raise-missing-from, # Python 2.7 compatibility
consider-using-f-string, # Python 2.7 compatibility

View File

@ -1,5 +1,76 @@
# Changelog
## [v0.4.11](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.11) (2023-07-26)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.10...v0.4.11)
**Implemented enhancements:**
- Add support for proxies [\#126](https://github.com/add-ons/plugin.video.viervijfzes/pull/126) ([michaelarnauts](https://github.com/michaelarnauts))
**Fixed bugs:**
- Add DRM support for all streams [\#121](https://github.com/add-ons/plugin.video.viervijfzes/pull/121) ([mediaminister](https://github.com/mediaminister))
- Use inputstreamhelper for unprotected MPEG-DASH [\#118](https://github.com/add-ons/plugin.video.viervijfzes/pull/118) ([mediaminister](https://github.com/mediaminister))
## [v0.4.10](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.10) (2023-01-16)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.9...v0.4.10)
**Fixed bugs:**
- Update api [\#114](https://github.com/add-ons/plugin.video.viervijfzes/pull/114) ([mediaminister](https://github.com/mediaminister))
## [v0.4.9](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.9) (2023-01-04)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.8...v0.4.9)
**Fixed bugs:**
- Add support for unprotected MPEG-DASH streams [\#111](https://github.com/add-ons/plugin.video.viervijfzes/pull/111) ([mediaminister](https://github.com/mediaminister))
- Fix clips [\#108](https://github.com/add-ons/plugin.video.viervijfzes/pull/108) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.8](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.8) (2022-07-07)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.7...v0.4.8)
**Fixed bugs:**
- Fix API [\#105](https://github.com/add-ons/plugin.video.viervijfzes/pull/105) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.7](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.7) (2022-02-04)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.6...v0.4.7)
**Fixed bugs:**
- Fix empty My List due to unknown items [\#102](https://github.com/add-ons/plugin.video.viervijfzes/pull/102) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.6](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.6) (2022-02-02)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.5...v0.4.6)
**Fixed bugs:**
- Fix playback of DRM protected content [\#101](https://github.com/add-ons/plugin.video.viervijfzes/pull/101) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.5](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.5) (2021-10-21)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.4...v0.4.5)
**Fixed bugs:**
- Remove dependency on inputstream.adaptive [\#98](https://github.com/add-ons/plugin.video.viervijfzes/pull/98) ([michaelarnauts](https://github.com/michaelarnauts))
- Various fixes due to layout changes [\#97](https://github.com/add-ons/plugin.video.viervijfzes/pull/97) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.4](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.4) (2021-09-15)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.3...v0.4.4)
**Fixed bugs:**
- Fix menu [\#93](https://github.com/add-ons/plugin.video.viervijfzes/pull/93) ([mediaminister](https://github.com/mediaminister))
## [v0.4.3](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.3) (2021-04-24)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.4.2...v0.4.3)
@ -37,11 +108,6 @@
- Fix error when requesting a My List that has not been created yet. [\#73](https://github.com/add-ons/plugin.video.viervijfzes/pull/73) ([michaelarnauts](https://github.com/michaelarnauts))
**Merged pull requests:**
- Cleanup CI [\#72](https://github.com/add-ons/plugin.video.viervijfzes/pull/72) ([michaelarnauts](https://github.com/michaelarnauts))
- Remove dependency on tox [\#70](https://github.com/add-ons/plugin.video.viervijfzes/pull/70) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.4.0](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.4.0) (2021-02-04)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.3.1...v0.4.0)
@ -50,12 +116,6 @@
- Rebranding to GoPlay [\#64](https://github.com/add-ons/plugin.video.viervijfzes/pull/64) ([michaelarnauts](https://github.com/michaelarnauts))
**Merged pull requests:**
- Make use of git archive [\#66](https://github.com/add-ons/plugin.video.viervijfzes/pull/66) ([dagwieers](https://github.com/dagwieers))
- Run CI on Windows [\#62](https://github.com/add-ons/plugin.video.viervijfzes/pull/62) ([michaelarnauts](https://github.com/michaelarnauts))
- Add support for Python 3.9 [\#60](https://github.com/add-ons/plugin.video.viervijfzes/pull/60) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.3.1](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.3.1) (2020-11-28)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.3.0...v0.3.1)
@ -64,10 +124,6 @@
- Fix authentication on some older Android devices [\#58](https://github.com/add-ons/plugin.video.viervijfzes/pull/58) ([michaelarnauts](https://github.com/michaelarnauts))
**Merged pull requests:**
- Fix CI tests [\#59](https://github.com/add-ons/plugin.video.viervijfzes/pull/59) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.3.0](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.3.0) (2020-11-17)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.2.0...v0.3.0)
@ -87,11 +143,6 @@
- Opening some programs without a title could throw an error [\#45](https://github.com/add-ons/plugin.video.viervijfzes/pull/45) ([dagwieers](https://github.com/dagwieers))
- Show message when Kodi Player fails to get the stream [\#40](https://github.com/add-ons/plugin.video.viervijfzes/pull/40) ([mediaminister](https://github.com/mediaminister))
**Merged pull requests:**
- Various fixes [\#46](https://github.com/add-ons/plugin.video.viervijfzes/pull/46) ([michaelarnauts](https://github.com/michaelarnauts))
- Use sake for Kodi stubs [\#36](https://github.com/add-ons/plugin.video.viervijfzes/pull/36) ([michaelarnauts](https://github.com/michaelarnauts))
## [v0.2.0](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.2.0) (2020-06-19)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/v0.1.0...v0.2.0)
@ -116,11 +167,6 @@
- Fix multi-line text in progress dialog [\#21](https://github.com/add-ons/plugin.video.viervijfzes/pull/21) ([mediaminister](https://github.com/mediaminister))
- Fix token encoding in auth [\#19](https://github.com/add-ons/plugin.video.viervijfzes/pull/19) ([michaelarnauts](https://github.com/michaelarnauts))
**Merged pull requests:**
- Check for unused translations [\#24](https://github.com/add-ons/plugin.video.viervijfzes/pull/24) ([michaelarnauts](https://github.com/michaelarnauts))
- Move test/ to tests/ [\#17](https://github.com/add-ons/plugin.video.viervijfzes/pull/17) ([dagwieers](https://github.com/dagwieers))
## [v0.1.0](https://github.com/add-ons/plugin.video.viervijfzes/tree/v0.1.0) (2020-03-27)
[Full Changelog](https://github.com/add-ons/plugin.video.viervijfzes/compare/89f55f70b017d0add645d1e1d88f0ce8192d11c4...v0.1.0)
@ -136,11 +182,7 @@
**Merged pull requests:**
- Improve CI tests [\#14](https://github.com/add-ons/plugin.video.viervijfzes/pull/14) ([michaelarnauts](https://github.com/michaelarnauts))
- Small translation fixes [\#12](https://github.com/add-ons/plugin.video.viervijfzes/pull/12) ([dagwieers](https://github.com/dagwieers))
- Various check fixes [\#11](https://github.com/add-ons/plugin.video.viervijfzes/pull/11) ([dagwieers](https://github.com/dagwieers))
- Replace Travis with GitHub Actions [\#10](https://github.com/add-ons/plugin.video.viervijfzes/pull/10) ([michaelarnauts](https://github.com/michaelarnauts))
- Improve code coverage [\#9](https://github.com/add-ons/plugin.video.viervijfzes/pull/9) ([michaelarnauts](https://github.com/michaelarnauts))

14
LICENSE
View File

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -645,14 +645,14 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,25 +1,12 @@
export KODI_HOME := $(CURDIR)/tests/home
export KODI_INTERACTIVE := 0
PYTHON := python
KODI_PYTHON_ABIS := 3.0.0 2.26.0
# Collect information to build as sensible package name
name = $(shell xmllint --xpath 'string(/addon/@id)' addon.xml)
version = $(shell xmllint --xpath 'string(/addon/@version)' addon.xml)
git_branch = $(shell git rev-parse --abbrev-ref HEAD)
git_hash = $(shell git rev-parse --short HEAD)
ifdef release
zip_name = $(name)-$(version).zip
else
zip_name = $(name)-$(version)-$(git_branch)-$(git_hash).zip
endif
zip_dir = $(name)/
languages = $(filter-out en_gb, $(patsubst resources/language/resource.language.%, %, $(wildcard resources/language/*)))
all: check test build
zip: build
multizip: build
check: check-pylint check-translations
@ -30,15 +17,15 @@ check-pylint:
check-translations:
@printf ">>> Running translation checks\n"
@$(foreach lang,$(languages), \
msgcmp resources/language/resource.language.$(lang)/strings.po resources/language/resource.language.en_gb/strings.po; \
msgcmp --use-untranslated resources/language/resource.language.$(lang)/strings.po resources/language/resource.language.en_gb/strings.po; \
)
@tests/check_for_unused_translations.py
@scripts/check_for_unused_translations.py
check-addon: clean build
check-addon: build
@printf ">>> Running addon checks\n"
$(eval TMPDIR := $(shell mktemp -d))
@unzip ../${zip_name} -d ${TMPDIR}
cd ${TMPDIR} && kodi-addon-checker --branch=leia
@unzip dist/plugin.video.viervijfzes-*+matrix.1.zip -d ${TMPDIR}
cd ${TMPDIR} && kodi-addon-checker --branch=matrix
@rm -rf ${TMPDIR}
codefix:
@ -56,17 +43,16 @@ clean:
@find . -name '__pycache__' -type d -delete
@rm -rf .pytest_cache/ tests/cdm tests/userdata/temp
@rm -f *.log .coverage
@rm -rf dist/
build: clean
@printf ">>> Building package\n"
@rm -f ../$(zip_name)
@git archive --format zip --worktree-attributes -v -o ../$(zip_name) --prefix $(zip_dir) $(or $(shell git stash create), HEAD)
@printf ">>> Successfully wrote package as: ../$(zip_name)\n"
@printf ">>> Building add-on\n"
@scripts/build.py
@ls -lah dist/*.zip
# You first need to run sudo gem install github_changelog_generator for this
release:
ifneq ($(release),)
@github_changelog_generator -u add-ons -p $(name) --no-issues --exclude-labels duplicate,question,invalid,wontfix release --future-release v$(release);
docker run -it --rm --env CHANGELOG_GITHUB_TOKEN=$(GH_TOKEN) -v "$(shell pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u add-ons -p plugin.video.viervijfzes --no-issues --exclude-labels duplicate,question,invalid,wontfix,release,testing --future-release v$(release)
@printf "cd /addon/@version\nset $$release\nsave\nbye\n" | xmllint --shell addon.xml; \
date=$(shell date '+%Y-%m-%d'); \
@ -80,11 +66,4 @@ else
@printf "Usage: make release release=1.0.0\n"
endif
multizip: clean
@-$(foreach abi,$(KODI_PYTHON_ABIS), \
printf "cd /addon/requires/import[@addon='xbmc.python']/@version\nset $(abi)\nsave\nbye\n" | xmllint --shell addon.xml; \
matrix=$(findstring $(abi), $(word 1,$(KODI_PYTHON_ABIS))); \
if [ $$matrix ]; then version=$(version)+matrix.1; else version=$(version); fi; \
printf "cd /addon/@version\nset $$version\nsave\nbye\n" | xmllint --shell addon.xml; \
make build; \
)
.PHONY: check codefix test clean build release

View File

@ -1,5 +1,5 @@
[![GitHub release](https://img.shields.io/github/release/add-ons/plugin.video.viervijfzes.svg?include_prereleases)](https://github.com/add-ons/plugin.video.viervijfzes/releases)
[![Build Status](https://img.shields.io/github/workflow/status/add-ons/plugin.video.viervijfzes/CI/master)](https://github.com/add-ons/plugin.video.viervijfzes/actions?query=branch%3Amaster)
[![GitHub release](https://img.shields.io/github/v/release/add-ons/plugin.video.viervijfzes?display_name=tag)](https://github.com/add-ons/plugin.video.viervijfzes/releases)
[![Build Status](https://img.shields.io/github/actions/workflow/status/add-ons/plugin.video.viervijfzes/ci.yml?branch=master)](https://github.com/add-ons/plugin.video.viervijfzes/actions?query=branch%3Amaster)
[![Codecov status](https://img.shields.io/codecov/c/github/add-ons/plugin.video.viervijfzes/master)](https://codecov.io/gh/add-ons/plugin.video.viervijfzes/branch/master)
[![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)
@ -11,7 +11,7 @@ account aanmaken op [goplay.be](https://www.goplay.be/).
Meer informatie kan je vinden op de [Wiki pagina](https://github.com/add-ons/plugin.video.viervijfzes/wiki).
> Let op dat er geen live-streams beschikbaar zijn op het GoPlay platform en je dus enkel kan kijken de beschikbare programma's in de catalogus.
> Let op dat er geen live-streams beschikbaar zijn op het GoPlay platform en je dus enkel kan kijken naar de beschikbare programma's in de catalogus.
## Features

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.viervijfzes" name="GoPlay" version="0.4.3" provider-name="Michaël Arnauts">
<addon id="plugin.video.viervijfzes" name="GoPlay" version="0.4.11" provider-name="Michaël Arnauts">
<requires>
<import addon="xbmc.python" version="2.26.0"/>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.6.0"/>
<import addon="script.module.inputstreamhelper" version="0.5.1"/>
<import addon="script.module.pysocks" version="1.6.8" optional="true"/>
<import addon="script.module.requests" version="2.22.0"/>
<import addon="script.module.routing" version="0.2.0"/>
<import addon="inputstream.adaptive" version="2.4.3"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon_entry.py">
<provides>video</provides>
@ -22,10 +21,8 @@
<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>
<license>GPL-3.0-only</license>
<news>v0.4.3 (2021-04-24)
- Add support for Play7.
- Improve error handling.
- Pass a week of EPG data to IPTV Manager.</news>
<news>v0.4.11 (2023-07-26)
- Fixes for DRM protected VOD.</news>
<source>https://github.com/add-ons/plugin.video.viervijfzes</source>
<assets>
<icon>resources/icon.png</icon>

View File

@ -4,7 +4,9 @@ pytest
pytest-cov
pytest-timeout
python-dateutil
pysocks
requests
git+git://github.com/dagwieers/kodi-plugin-routing.git@setup#egg=routing
git+https://github.com/tamland/kodi-plugin-routing@master#egg=routing
six
sakee
win-inet-pton; platform_system=="Windows"

View File

@ -60,6 +60,10 @@ msgstr ""
### SUBMENUS
msgctxt "#30052"
msgid "Watch live [B]{channel}[/B]"
msgstr ""
msgctxt "#30053"
msgid "TV Guide for [B]{channel}[/B]"
msgstr ""

View File

@ -61,6 +61,10 @@ msgstr "Tv-gids"
### SUBMENUS
msgctxt "#30052"
msgid "Watch live [B]{channel}[/B]"
msgstr "Kijk live [B]{channel}[/B]"
msgctxt "#30053"
msgid "TV Guide for [B]{channel}[/B]"
msgstr "Tv-gids voor [B]{channel}[/B]"

View File

@ -160,11 +160,11 @@ def play_epg(channel, timestamp):
@routing.route('/play/catalog')
@routing.route('/play/catalog/<uuid>')
def play_catalog(uuid=None):
@routing.route('/play/catalog/<uuid>/<content_type>')
def play_catalog(uuid=None, content_type=None):
""" Play the requested item """
from resources.lib.modules.player import Player
Player().play(uuid)
Player().play(uuid, content_type)
@routing.route('/play/page/<page>')

View File

@ -17,19 +17,20 @@ try: # Python 3
from html import unescape
except ImportError: # Python 2
from HTMLParser import HTMLParser
unescape = HTMLParser().unescape
ADDON = xbmcaddon.Addon()
SORT_METHODS = dict(
unsorted=xbmcplugin.SORT_METHOD_UNSORTED,
label=xbmcplugin.SORT_METHOD_LABEL_IGNORE_FOLDERS,
title=xbmcplugin.SORT_METHOD_TITLE,
episode=xbmcplugin.SORT_METHOD_EPISODE,
duration=xbmcplugin.SORT_METHOD_DURATION,
year=xbmcplugin.SORT_METHOD_VIDEO_YEAR,
date=xbmcplugin.SORT_METHOD_DATE,
)
SORT_METHODS = {
'unsorted': xbmcplugin.SORT_METHOD_UNSORTED,
'label': xbmcplugin.SORT_METHOD_LABEL_IGNORE_FOLDERS,
'title': xbmcplugin.SORT_METHOD_TITLE,
'episode': xbmcplugin.SORT_METHOD_EPISODE,
'duration': xbmcplugin.SORT_METHOD_DURATION,
'year': xbmcplugin.SORT_METHOD_VIDEO_YEAR,
'date': xbmcplugin.SORT_METHOD_DATE
}
DEFAULT_SORT_METHODS = [
'unsorted', 'title'
]
@ -259,12 +260,17 @@ def play(stream, stream_type=STREAM_HLS, license_key=None, title=None, art_dict=
elif stream_type == STREAM_DASH:
play_item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
play_item.setMimeType('application/dash+xml')
import inputstreamhelper
if license_key is not None:
import inputstreamhelper
# DRM protected MPEG-DASH
is_helper = inputstreamhelper.Helper('mpd', drm='com.widevine.alpha')
if is_helper.check_inputstream():
play_item.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')
play_item.setProperty('inputstream.adaptive.license_key', license_key)
else:
# Unprotected MPEG-DASH
is_helper = inputstreamhelper.Helper('mpd')
is_helper.check_inputstream()
play_item.setContentLookup(False)
@ -464,13 +470,74 @@ def open_settings():
def get_global_setting(key):
"""Get a Kodi setting"""
result = jsonrpc(method='Settings.GetSettingValue', params=dict(setting=key))
result = jsonrpc(method='Settings.GetSettingValue', params={'setting': key})
return result.get('result', {}).get('value')
def set_global_setting(key, value):
"""Set a Kodi setting"""
return jsonrpc(method='Settings.SetSettingValue', params=dict(setting=key, value=value))
return jsonrpc(method='Settings.SetSettingValue', params={'setting': key, 'value': value})
def has_socks():
"""Test if socks is installed, and use a static variable to remember"""
if hasattr(has_socks, 'cached'):
return getattr(has_socks, 'cached')
try:
import socks # noqa: F401; pylint: disable=unused-variable,unused-import
except ImportError:
has_socks.cached = False
return None # Detect if this is the first run
has_socks.cached = True
return True
def get_proxies():
"""Return a usable proxies dictionary from Kodi proxy settings"""
# Use proxy settings from environment variables
env_http_proxy = os.environ.get('HTTP_PROXY')
env_https_proxy = os.environ.get('HTTPS_PROXY')
if env_http_proxy:
return {'http': env_http_proxy, 'https': env_https_proxy or env_http_proxy}
usehttpproxy = get_global_setting('network.usehttpproxy')
if usehttpproxy is not True:
return None
try:
httpproxytype = int(get_global_setting('network.httpproxytype'))
except ValueError:
httpproxytype = 0
socks_supported = has_socks()
if httpproxytype != 0 and not socks_supported:
# Only open the dialog the first time (to avoid multiple popups)
if socks_supported is None:
ok_dialog('', localize(30966)) # Requires PySocks
return None
proxy_types = ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']
proxy = {
'scheme': proxy_types[httpproxytype] if 0 <= httpproxytype < 5 else 'http',
'server': get_global_setting('network.httpproxyserver'),
'port': get_global_setting('network.httpproxyport'),
'username': get_global_setting('network.httpproxyusername'),
'password': get_global_setting('network.httpproxypassword')
}
if proxy.get('username') and proxy.get('password') and proxy.get('server') and proxy.get('port'):
proxy_address = '{scheme}://{username}:{password}@{server}:{port}'.format(**proxy)
elif proxy.get('username') and proxy.get('server') and proxy.get('port'):
proxy_address = '{scheme}://{username}@{server}:{port}'.format(**proxy)
elif proxy.get('server') and proxy.get('port'):
proxy_address = '{scheme}://{server}:{port}'.format(**proxy)
elif proxy.get('server'):
proxy_address = '{scheme}://{server}'.format(**proxy)
else:
return None
return {'http': proxy_address, 'https': proxy_address}
def get_cond_visibility(condition):

View File

@ -4,9 +4,6 @@
from __future__ import absolute_import, division, unicode_literals
import logging
from datetime import datetime
import dateutil.tz
from resources.lib import kodiutils
from resources.lib.kodiutils import TitleItem
@ -113,7 +110,7 @@ class Catalog:
},
info_dict={
'tvshowtitle': program.title,
'title': kodiutils.localize(30205, season=season.number), # Season {season}
'title': kodiutils.localize(30205, season=season.number) if season.number else season.title, # Season {season}
'plot': season.description or program.description,
'set': program.title,
}
@ -243,7 +240,8 @@ class Catalog:
listing = []
for episode in episodes:
title_item = Menu.generate_titleitem(episode)
title_item.info_dict['title'] = episode.program_title + ' - ' + title_item.title
if episode.program_title:
title_item.info_dict['title'] = episode.program_title + ' - ' + title_item.title
listing.append(title_item)
for program in programs:
@ -252,22 +250,10 @@ class Catalog:
kodiutils.show_listing(listing, 30005, content='tvshows')
def show_mylist(self):
""" Show all the programs of all channels """
try:
mylist, _ = self._auth.get_dataset('myList', 'myList')
except Exception as ex:
kodiutils.notification(message=str(ex))
raise
""" Show the programs of My List """
mylist = self._api.get_mylist()
items = []
if mylist:
for item in mylist:
program = self._api.get_program_by_uuid(item.get('id'))
if program:
program.my_list = True
items.append(program)
listing = [Menu.generate_titleitem(item) for item in items]
listing = [Menu.generate_titleitem(item) for item in mylist]
# Sort items by title
# Used for A-Z listing or when movies and episodes are mixed.
@ -279,23 +265,7 @@ class Catalog:
kodiutils.end_of_directory()
return
mylist, sync_info = self._auth.get_dataset('myList', 'myList')
if not mylist:
mylist = []
if uuid not in [item.get('id') for item in mylist]:
# Python 2.7 doesn't support .timestamp(), and windows doesn't do '%s', so we need to calculate it ourself
epoch = datetime(1970, 1, 1, tzinfo=dateutil.tz.gettz('UTC'))
now = datetime.now(tz=dateutil.tz.gettz('UTC'))
timestamp = int((now - epoch).total_seconds()) * 1000
mylist.append({
'id': uuid,
'timestamp': timestamp,
})
self._auth.put_dataset('myList', 'myList', mylist, sync_info)
self._api.mylist_add(uuid)
kodiutils.end_of_directory()
@ -305,12 +275,6 @@ class Catalog:
kodiutils.end_of_directory()
return
mylist, sync_info = self._auth.get_dataset('myList', 'myList')
if not mylist:
mylist = []
new_mylist = [item for item in mylist if item.get('id') != uuid]
self._auth.put_dataset('myList', 'myList', new_mylist, sync_info)
self._api.mylist_del(uuid)
kodiutils.end_of_directory()

View File

@ -71,9 +71,27 @@ class Channels:
# 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'))
icon = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel_info.get('logo'))
listing = []
listing.append(
TitleItem(
title=kodiutils.localize(30052, channel=channel_info.get('name')), # Watch live {channel}
path=kodiutils.url_for('play_live', channel=channel_info.get('name')) + '?.pvr',
art_dict={
'icon': icon,
'fanart': fanart,
},
info_dict={
'plot': kodiutils.localize(30052, channel=channel_info.get('name')), # Watch live {channel}
'playcount': 0,
'mediatype': 'video',
},
is_playable=True,
)
)
if channel_info.get('epg_id'):
listing.append(
TitleItem(

View File

@ -4,7 +4,7 @@
from __future__ import absolute_import, division, unicode_literals
import logging
from datetime import timedelta, datetime
from datetime import datetime, timedelta
from resources.lib import kodiutils
from resources.lib.viervijfzes import CHANNELS
@ -42,17 +42,17 @@ class IPTVManager:
streams = []
for key, channel in CHANNELS.items():
if channel.get('iptv_id'):
streams.append(dict(
id=channel.get('iptv_id'),
name=channel.get('name'),
logo='special://home/addons/{addon}/resources/logos/{logo}'.format(addon=kodiutils.addon_id(),
logo=channel.get('logo')),
preset=channel.get('iptv_preset'),
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({
'id': channel.get('iptv_id'),
'name': channel.get('name'),
'logo': 'special://home/addons/{addon}/resources/logos/{logo}'.format(addon=kodiutils.addon_id(),
logo=channel.get('logo')),
'preset': channel.get('iptv_preset'),
'stream': 'plugin://plugin.video.viervijfzes/play/live/{channel}'.format(channel=key),
'vod': 'plugin://plugin.video.viervijfzes/play/epg/{channel}/{{date}}'.format(channel=key)
})
return dict(version=1, streams=streams)
return {'version': 1, 'streams': streams}
@via_socket
def send_epg(): # pylint: disable=no-method-argument
@ -78,20 +78,21 @@ class IPTVManager:
epg = epg_api.get_epg(key, date.strftime('%Y-%m-%d'))
results[iptv_id].extend([
dict(
start=program.start.isoformat(),
stop=(program.start + timedelta(seconds=program.duration)).isoformat(),
title=program.program_title,
subtitle=program.episode_title,
description=program.description,
episode='S%sE%s' % (program.season, program.number) if program.season and program.number else None,
genre=program.genre,
genre_id=program.genre_id,
image=program.thumb,
stream=kodiutils.url_for('play_from_page',
channel=key,
page=quote(program.video_url, safe='')) if program.video_url else None)
{
'start': program.start.isoformat(),
'stop': (program.start + timedelta(seconds=program.duration)).isoformat(),
'title': program.program_title,
'subtitle': program.episode_title,
'description': program.description,
'episode': 'S%sE%s' % (program.season, program.number) if program.season and program.number else None,
'genre': program.genre,
'genre_id': program.genre_id,
'image': program.thumb,
'stream': kodiutils.url_for('play_from_page',
channel=key,
page=quote(program.video_url, safe='')) if program.video_url else None
}
for program in epg if program.duration
])
return dict(version=1, epg=results)
return {'version': 1, 'epg': results}

View File

@ -31,68 +31,68 @@ class Menu:
TitleItem(
title=kodiutils.localize(30001), # A-Z
path=kodiutils.url_for('show_catalog'),
art_dict=dict(
icon='DefaultMovieTitle.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30002),
)
art_dict={
'icon': 'DefaultMovieTitle.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30002)
}
),
TitleItem(
title=kodiutils.localize(30007), # TV Channels
path=kodiutils.url_for('show_channels'),
art_dict=dict(
icon='DefaultAddonPVRClient.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30008),
)
art_dict={
'icon': 'DefaultAddonPVRClient.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30008)
}
),
TitleItem(
title=kodiutils.localize(30003), # Catalog
path=kodiutils.url_for('show_categories'),
art_dict=dict(
icon='DefaultGenre.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30004),
)
art_dict={
'icon': 'DefaultGenre.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30004)
}
),
TitleItem(
title=kodiutils.localize(30005), # Recommendations
path=kodiutils.url_for('show_recommendations'),
art_dict=dict(
icon='DefaultFavourites.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30006),
)
art_dict={
'icon': 'DefaultFavourites.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30006)
}
),
TitleItem(
title=kodiutils.localize(30011), # My List
path=kodiutils.url_for('show_mylist'),
art_dict=dict(
icon='DefaultPlaylist.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30012),
)
art_dict={
'icon': 'DefaultPlaylist.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30012)
}
),
TitleItem(
title=kodiutils.localize(30009), # Search
path=kodiutils.url_for('show_search'),
art_dict=dict(
icon='DefaultAddonsSearch.png',
fanart=kodiutils.get_addon_info('fanart'),
),
info_dict=dict(
plot=kodiutils.localize(30010),
)
art_dict={
'icon': 'DefaultAddonsSearch.png',
'fanart': kodiutils.get_addon_info('fanart')
},
info_dict={
'plot': kodiutils.localize(30010)
}
)
]
@ -183,7 +183,7 @@ class Menu:
if item.uuid:
# We have an UUID and can play this item directly
path = kodiutils.url_for('play_catalog', uuid=item.uuid)
path = kodiutils.url_for('play_catalog', uuid=item.uuid, content_type=item.content_type)
else:
# We don't have an UUID, and first need to fetch the video information from the page
path = kodiutils.url_for('play_from_page', page=quote(item.path, safe=''))

View File

@ -12,11 +12,6 @@ from resources.lib.viervijfzes.auth import AuthApi
from resources.lib.viervijfzes.aws.cognito_idp import AuthenticationException, InvalidLoginException
from resources.lib.viervijfzes.content import CACHE_PREVENT, ContentApi, GeoblockedException, UnavailableException
try: # Python 3
from urllib.parse import quote, urlencode
except ImportError: # Python 2
from urllib import quote, urlencode
_LOGGER = logging.getLogger(__name__)
@ -31,8 +26,7 @@ class Player:
# Workaround for Raspberry Pi 3 and older
kodiutils.set_global_setting('videoplayer.useomxplayer', True)
@staticmethod
def live(channel):
def live(self, channel):
""" Play the live channel.
:type channel: string
"""
@ -43,9 +37,9 @@ class Player:
# self.play_from_page(broadcast.video_url)
# return
channel_name = CHANNELS.get(channel, dict(name=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()
channel_url = CHANNELS.get(channel, {'url': channel}).get('url')
self.play_from_page(channel_url)
def play_from_page(self, path):
""" Play the requested item.
@ -74,51 +68,36 @@ class Player:
if episode.uuid:
# Lookup the stream
resolved_stream = self._resolve_stream(episode.uuid)
resolved_stream = self._resolve_stream(episode.uuid, episode.content_type)
_LOGGER.debug('Resolved stream: %s', resolved_stream)
if resolved_stream:
titleitem = Menu.generate_titleitem(episode)
if resolved_stream.license_url:
# Generate license key
license_key = self.create_license_key(resolved_stream.license_url,
key_headers=dict(
customdata=resolved_stream.auth,
))
else:
license_key = None
kodiutils.play(resolved_stream.url,
resolved_stream.stream_type,
license_key,
resolved_stream.license_key,
info_dict=titleitem.info_dict,
art_dict=titleitem.art_dict,
prop_dict=titleitem.prop_dict)
def play(self, uuid):
def play(self, uuid, content_type):
""" Play the requested item.
:type uuid: string
:type content_type: string
"""
if not uuid:
kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable...
return
# Lookup the stream
resolved_stream = self._resolve_stream(uuid)
if resolved_stream.license_url:
# Generate license key
license_key = self.create_license_key(resolved_stream.license_url, key_headers=dict(
customdata=resolved_stream.auth,
))
else:
license_key = None
kodiutils.play(resolved_stream.url, resolved_stream.stream_type, license_key)
resolved_stream = self._resolve_stream(uuid, content_type)
kodiutils.play(resolved_stream.url, resolved_stream.stream_type, resolved_stream.license_key)
@staticmethod
def _resolve_stream(uuid):
def _resolve_stream(uuid, content_type):
""" Resolve the stream for the requested item
:type uuid: string
:type content_type: string
"""
try:
# Check if we have credentials
@ -135,7 +114,7 @@ class Player:
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path())
# Get stream information
resolved_stream = ContentApi(auth).get_stream_by_uuid(uuid)
resolved_stream = ContentApi(auth).get_stream_by_uuid(uuid, content_type)
return resolved_stream
except (InvalidLoginException, AuthenticationException) as ex:
@ -151,26 +130,3 @@ class Player:
except UnavailableException:
kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable...
return None
@staticmethod
def create_license_key(key_url, key_type='R', key_headers=None, key_value=None):
""" Create a license key string that we need for inputstream.adaptive.
:param str key_url:
:param str key_type:
:param dict[str, str] key_headers:
:param str key_value:
:rtype: str
"""
header = ''
if key_headers:
header = urlencode(key_headers)
if key_type in ('A', 'R', 'B'):
key_value = key_type + '{SSM}'
elif key_type == 'D':
if 'D{SSM}' not in key_value:
raise ValueError('Missing D{SSM} placeholder')
key_value = quote(key_value)
return '%s|%s|%s|' % (key_url, header, key_value)

View File

@ -125,7 +125,7 @@ class KodiPlayer(Player):
if not self.av_started:
# Check stream path
import requests
response = requests.get(self.stream_path)
response = requests.get(self.stream_path, timeout=5)
if response.status_code == 403:
message_id = 30720
else:

View File

@ -5,68 +5,59 @@ from __future__ import absolute_import, division, unicode_literals
from collections import OrderedDict
CHANNELS = OrderedDict([
('Play4', dict(
name='Play4',
epg_id='vier',
logo='play4.png',
background='play4-background.png',
iptv_preset=4,
iptv_id='play4.be',
youtube=[
dict(
label='GoPlay',
logo='goplay.png',
path='plugin://plugin.video.youtube/user/viertv/',
),
],
)),
('Play5', dict(
name='Play5',
epg_id='vijf',
logo='play5.png',
background='play5-background.png',
iptv_preset=5,
iptv_id='play5.be',
youtube=[
dict(
label='GoPlay',
logo='goplay.png',
path='plugin://plugin.video.youtube/user/viertv/',
),
],
)),
('Play6', dict(
name='Play6',
epg_id='zes',
logo='play6.png',
background='play6-background.png',
iptv_preset=6,
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=17,
iptv_id='play7.be',
youtube=[],
)),
('GoPlay', dict(
name='Go Play',
url='https://www.goplay.be',
logo='goplay.png',
background='goplay-background.png',
youtube=[],
))
('Play4', {
'name': 'Play4',
'url': 'live-kijken/play-4',
'epg_id': 'vier',
'logo': 'play4.png',
'background': 'play4-background.png',
'iptv_preset': 4,
'iptv_id': 'play4.be',
'youtube': [
{'label': 'GoPlay', 'logo': 'goplay.png', 'path': 'plugin://plugin.video.youtube/user/viertv/'},
]
}),
('Play5', {
'name': 'Play5',
'url': 'live-kijken/play-5',
'epg_id': 'vijf',
'logo': 'play5.png',
'background': 'play5-background.png',
'iptv_preset': 5,
'iptv_id': 'play5.be',
'youtube': [
{'label': 'GoPlay', 'logo': 'goplay.png', 'path': 'plugin://plugin.video.youtube/user/viertv/'},
]
}),
('Play6', {
'name': 'Play6',
'url': 'live-kijken/play-6',
'epg_id': 'zes',
'logo': 'play6.png',
'background': 'play6-background.png',
'iptv_preset': 6,
'iptv_id': 'play6.be',