-
Notifications
You must be signed in to change notification settings - Fork 456
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4591 from mcr222/omega
[plugin.video.rtve]v1.0.0
- Loading branch information
Showing
18 changed files
with
814 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# plugin.video.rtve | ||
Kodi addon RTVE. | ||
Entertainment, news, sports, documentaries, etc from spanish television https://www.rtve.es/play/ | ||
|
||
Complement per Kodi - XBMC. | ||
Toda la programación de RTVE. | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from logging import DEBUG | ||
|
||
import xbmc | ||
import sys | ||
import urllib.parse | ||
import xbmcplugin | ||
from resources.lib.ui.UI import UI | ||
|
||
addon_handle = int(sys.argv[1]) | ||
args = urllib.parse.parse_qs(sys.argv[2][1:]) | ||
|
||
xbmc.log("plugin.video.rtve - addon.py - args: " + str(args), xbmc.LOGDEBUG) | ||
|
||
xbmcplugin.setContent(addon_handle, 'movies') | ||
|
||
ui = UI(sys.argv[0], addon_handle, args) | ||
ui.run(args.get('mode', None), args.get('url', [''])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<addon id="plugin.video.rtve" name="RTVE" version="1.0.0" provider-name="mcr222"> | ||
<requires> | ||
<import addon="xbmc.python" version="3.0.0"/> | ||
<import addon="script.module.future" version="1.0.0"/> | ||
<import addon="script.module.inputstreamhelper" version="0.4.2"/> | ||
</requires> | ||
<extension point="xbmc.python.pluginsource" library="addon.py"> | ||
<provides>video</provides> | ||
</extension> | ||
<extension point="xbmc.addon.metadata"> | ||
<platform>all</platform> | ||
<summary lang="en_GB">Entertainment, news, documentaries, etc from spanish television https://www.rtve.es/play/</summary> | ||
<description lang="en_GB">Entertainment, news, documentaries, etc from spanish television https://www.rtve.es/play/. </description> | ||
<summary lang="ca_ES">Tots els programes de RTVE.</summary> | ||
<description lang="ca_ES">Tota la programació de RTVE.</description> | ||
<summary lang="es_ES">Toda la programación de RTVE</summary> | ||
<description lang="es_ES">Toda la programación de RTVE</description> | ||
<language>ca</language> | ||
<license>GPL-2.0-or-later</license> | ||
<source>https://github.com/mcr222/plugin.video.rtve</source> | ||
<website>https://www.rtve.es/play/</website> | ||
<assets> | ||
<icon>resources/icon.png</icon> | ||
<fanart>resources/fanart.jpg</fanart> | ||
</assets> | ||
</extension> | ||
</addon> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
v1.0.0 | ||
- First version |
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from __future__ import division | ||
|
||
import json | ||
from builtins import object | ||
from logging import DEBUG | ||
|
||
from resources.lib.video.FolderVideo import FolderVideo | ||
from resources.lib.utils.Utils import * | ||
import xbmc | ||
|
||
from resources.lib.video.Video import Video | ||
|
||
|
||
class rtve(object): | ||
def __init__(self, addon): | ||
xbmc.log("plugin.video.rtve classe rtve - init() ", xbmc.LOGDEBUG) | ||
|
||
# mode = None | ||
def listHome(self): | ||
xbmc.log("plugin.video.rtve classe rtve - listHome() ", xbmc.LOGDEBUG) | ||
coleccions = FolderVideo('Television', "https://api.rtve.es/api/tematicas/823", "getProgrames", "", | ||
"") | ||
return [coleccions] | ||
|
||
def listProgrames(self, urlApi): | ||
xbmc.log("plugin.video.rtve - programas " + urlApi, xbmc.LOGDEBUG) | ||
folders = [] | ||
videos = [] | ||
|
||
hijosJson ="hijos.json?page=" | ||
videosJson = "videos.json?page=" | ||
hijosUrl = "" | ||
if hijosJson in urlApi: | ||
hijosUrl = urlApi | ||
elif not videosJson in urlApi: | ||
hijosUrl = urlApi + "/" + hijosJson + "1" | ||
|
||
if hijosUrl: | ||
split = hijosUrl.split("=") | ||
currentPage = int(split[1]) | ||
nextHijosUrl = split[0] + "=" + str(currentPage+1) | ||
previousHijosUrl = "" | ||
if currentPage>1: | ||
previousHijosUrl = split[0] + "=" + str(currentPage - 1) | ||
|
||
videosUrl = "" | ||
if videosJson in urlApi: | ||
videosUrl = urlApi | ||
elif not hijosJson in urlApi: | ||
videosUrl = urlApi + "/" + videosJson +"1" | ||
|
||
if videosUrl: | ||
split = videosUrl.split("=") | ||
currentPage = int(split[1]) | ||
nextVideosUrl = split[0] + "=" + str(currentPage + 1) | ||
previousVideosUrl = "" | ||
if currentPage > 1: | ||
previousVideosUrl = split[0] + "=" + str(currentPage - 1) | ||
|
||
if hijosUrl: | ||
hijosItems = getJsonData(hijosUrl)['page']['items'] | ||
if len(hijosItems)>0: | ||
|
||
for item in hijosItems: | ||
xbmc.log("plugin.video.rtve - element " + str(item), xbmc.LOGDEBUG) | ||
itemid = item['id'] | ||
programa_url = "https://www.rtve.es/api/programas/{}".format(itemid) | ||
img="" | ||
try: | ||
programaJson = getJsonData(programa_url, 1)['page']['items'][0] | ||
img = programaJson.get('imgPoster', "") | ||
if not img: | ||
img = programaJson.get('imgCol', "") | ||
if not img: | ||
img = programaJson.get('thumbnail', "") | ||
if not img: | ||
img = programaJson.get('imgBackground', "") | ||
except Exception as e: | ||
img="" | ||
|
||
foldVideo = FolderVideo(item['title'], "https://api.rtve.es/api/tematicas/" + itemid, 'getProgrames', img, img) | ||
folders.append(foldVideo) | ||
|
||
if previousHijosUrl: | ||
folders.append(FolderVideo("Anterior Pag", previousHijosUrl, 'getProgrames')) | ||
|
||
folders.append(FolderVideo("Siguiente Pag", nextHijosUrl, 'getProgrames')) | ||
return (folders, videos) | ||
|
||
if videosUrl: | ||
videosItems = getJsonData(videosUrl)['page']['items'] | ||
if len(videosItems)>0: | ||
for item in videosItems: | ||
xbmc.log("plugin.video.rtve - element " + str(item), xbmc.LOGDEBUG) | ||
img = item['thumbnail'] | ||
video = Video(item['title'], img, img, item['description'], item['id'], "") | ||
videos.append(video) | ||
|
||
if previousVideosUrl: | ||
folders.append(FolderVideo("Anterior Pag", previousVideosUrl, 'getProgrames')) | ||
|
||
folders.append(FolderVideo("Siguiente Pag", nextVideosUrl, 'getProgrames')) | ||
|
||
return (folders, videos) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
from builtins import str | ||
from builtins import object | ||
from logging import DEBUG | ||
|
||
from resources.lib.utils.Utils import buildUrl, getJsonData | ||
from resources.lib.rtve.rtve import rtve | ||
import xbmcaddon | ||
import xbmcplugin | ||
import xbmcgui | ||
import xbmc | ||
import xbmcvfs | ||
import time | ||
|
||
class UI(object): | ||
|
||
def __init__(self, base_url, addon_handle, args): | ||
xbmc.log("plugin.video.rtve classe UI - start init() ", xbmc.LOGDEBUG) | ||
addon = xbmcaddon.Addon() | ||
self.rtve = rtve(addon) | ||
self.base_url = base_url | ||
self.addon_handle = addon_handle | ||
self.args = args | ||
self.mode = args.get('mode', None) | ||
self.url = args.get('url', ['']) | ||
xbmc.log("plugin.video.rtve classe UI - finish init()", xbmc.LOGDEBUG) | ||
|
||
|
||
def run(self, mode, url): | ||
xbmc.log("plugin.video.rtve classe UI - run() mode = " + str(mode) + ", url " + str(url), xbmc.LOGDEBUG) | ||
|
||
if mode == None: | ||
xbmc.log("plugin.video.rtve classe UI - mode = None", xbmc.LOGDEBUG) | ||
lFolder = self.rtve.listHome() | ||
|
||
if len(lFolder) > 0: | ||
self.listFolder(lFolder) | ||
else: | ||
xbmc.log("plugin.video.rtve - UI.run() Home - No existeixen elements", xbmc.LOGDEBUG) | ||
|
||
elif mode[0] == 'getProgrames': | ||
xbmc.log("plugin.video.rtve - Programes", xbmc.LOGDEBUG) | ||
(folders, videos) = self.rtve.listProgrames(url[0]) | ||
self.listFolder(folders, False) | ||
self.listVideos(videos) | ||
|
||
elif mode[0] == 'playVideo': | ||
self.playVideo(url[0]) | ||
|
||
def listVideos(self, lVideos): | ||
xbmc.log("plugin.video.rtve - UI - listVideos - Numero videos: " + str(len(lVideos)), xbmc.LOGDEBUG) | ||
|
||
for video in lVideos: | ||
# Create a list item with a text label | ||
list_item = xbmcgui.ListItem(label=video.title) | ||
# Set graphics (thumbnail, fanart, banner, poster, landscape etc.) for the list item. | ||
# Here we use only poster for simplicity's sake. | ||
# In a real-life plugin you may need to set multiple image types. | ||
list_item.setArt({'poster': video.iconImage}) | ||
list_item.setProperty('IsPlayable', 'true') | ||
# Set additional info for the list item via InfoTag. | ||
# 'mediatype' is needed for skin to display info for this ListItem correctly. | ||
info_tag = list_item.getVideoInfoTag() | ||
info_tag.setMediaType('movie') | ||
info_tag.setTitle(video.title) | ||
info_tag.setPlot(video.information) | ||
# Set 'IsPlayable' property to 'true'. | ||
|
||
url = video.url | ||
# Add the list item to a virtual Kodi folder. | ||
# is_folder = False means that this item won't open any sub-list. | ||
is_folder = False | ||
# Add our item to the Kodi virtual folder listing. | ||
xbmc.log("plugin.video.rtve - UI - directory item " + str(url), xbmc.LOGDEBUG) | ||
urlPlugin = buildUrl({'mode': 'playVideo', 'url': url}, self.base_url) | ||
|
||
xbmcplugin.addDirectoryItem(self.addon_handle, urlPlugin, list_item, is_folder) | ||
# Add sort methods for the virtual folder items | ||
xbmcplugin.addSortMethod(self.addon_handle, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) | ||
xbmcplugin.addSortMethod(self.addon_handle, xbmcplugin.SORT_METHOD_VIDEO_YEAR) | ||
|
||
# Finish creating a virtual folder. | ||
xbmcplugin.endOfDirectory(self.addon_handle) | ||
|
||
def listFolder(self, lFolderVideos, enddirectory=True): | ||
xbmc.log("plugin.video.rtve classe UI - listFolder", xbmc.LOGDEBUG) | ||
for folder in lFolderVideos: | ||
|
||
mode = folder.mode | ||
name = folder.name | ||
url = folder.url | ||
iconImage = folder.iconImage | ||
thumbImage = folder.thumbnailImage | ||
|
||
urlPlugin = buildUrl({'mode': mode, 'url': url}, self.base_url) | ||
liz = xbmcgui.ListItem(name) | ||
liz.setInfo(type="Video", infoLabels={"title": name}) | ||
liz.setArt({'thumb': thumbImage, 'icon' : iconImage}) | ||
|
||
xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=urlPlugin, listitem=liz, isFolder=True) | ||
|
||
if enddirectory: | ||
xbmcplugin.endOfDirectory(self.addon_handle) | ||
|
||
class DRMStreamPlayer(xbmc.Player): | ||
def __init__(self): | ||
super().__init__() | ||
self.is_playing = False | ||
self.playback_error = False | ||
|
||
def onPlayBackStarted(self): | ||
self.is_playing = True | ||
xbmc.log('Playback started successfully', xbmc.LOGDEBUG) | ||
|
||
def onPlayBackError(self): | ||
self.playback_error = True | ||
xbmc.log('Playback error occurred', xbmc.LOGERROR) | ||
|
||
def onPlayBackStopped(self): | ||
self.is_playing = False | ||
|
||
def playVideo(self,videoId): | ||
xbmc.log("plugin.video.rtve -UI - playVideo " + str(videoId), xbmc.LOGDEBUG) | ||
|
||
stream_url = "https://ztnr.rtve.es/ztnr/{}.mpd".format(videoId) | ||
xbmc.log("plugin.video.rtve - UI - playVideo apijson url" + str(stream_url), xbmc.LOGDEBUG) | ||
|
||
license_url = "" | ||
try: | ||
tokenUrl = "https://api.rtve.es/api/token/{}".format(videoId) | ||
tokenJson = getJsonData(tokenUrl) | ||
|
||
xbmc.log("plugin.video.rtve - UI - playVideo token json" + str(tokenJson), xbmc.LOGDEBUG) | ||
|
||
license_url = tokenJson['widevineURL'] | ||
xbmc.log("plugin.video.rtve - UI - playVideo widevine url" + str(license_url), xbmc.LOGDEBUG) | ||
except Exception as e: | ||
xbmc.log(f'Error playing DRM stream: {str(e)}', xbmc.LOGERROR) | ||
|
||
|
||
from inputstreamhelper import Helper # pylint: disable=import-outside-toplevel | ||
from urllib.parse import quote | ||
|
||
# Constants | ||
PROTOCOL = 'mpd' | ||
DRM = 'com.widevine.alpha' | ||
|
||
# HTTP headers | ||
headers = { | ||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', | ||
'Referer': 'https://www.rtve.es/', | ||
'Origin': 'https://www.rtve.es', | ||
'Accept': '*/*' | ||
} | ||
|
||
# Convert headers to Kodi format | ||
headers_string = '&'.join([f'{k}={quote(v)}' for k, v in headers.items()]) | ||
|
||
try: | ||
# Initialize custom player | ||
player = self.DRMStreamPlayer() | ||
|
||
# Create and configure the ListItem | ||
play_item = xbmcgui.ListItem(path=stream_url) | ||
|
||
# Set required properties for DRM playback | ||
play_item.setProperty('inputstream', 'inputstream.adaptive') | ||
play_item.setProperty('inputstream.adaptive.manifest_type', PROTOCOL) | ||
play_item.setProperty('inputstream.adaptive.manifest_headers', headers_string) | ||
play_item.setProperty('inputstream.adaptive.stream_headers', headers_string) | ||
|
||
# Configure license key with proper formatting and increased timeout | ||
if license_url: | ||
play_item.setProperty('inputstream.adaptive.license_type', DRM) | ||
play_item.setProperty('inputstream.adaptive.license_key', license_url) | ||
|
||
# Set additional properties | ||
play_item.setMimeType('application/dash+xml') | ||
play_item.setContentLookup(False) | ||
|
||
# Add properties to help with buffering | ||
play_item.setProperty('inputstream.adaptive.stream_selection_type', 'adaptive') | ||
|
||
# Adjust these buffering settings | ||
play_item.setProperty('inputstream.adaptive.stream_buffer_size', '524288') # Doubled buffer | ||
play_item.setProperty('inputstream.adaptive.initial_buffer_duration', '15') | ||
play_item.setProperty('inputstream.adaptive.persistent_storage', 'true') | ||
play_item.setProperty('inputstream.adaptive.max_bandwidth', '20000000') | ||
play_item.setProperty('inputstream.adaptive.min_bandwidth', '500000') | ||
|
||
# Start playback | ||
xbmcplugin.setResolvedUrl(handle=self.addon_handle, succeeded=True, listitem=play_item) | ||
|
||
# Log success | ||
xbmc.log('DRM Stream playback initiated successfully', xbmc.LOGDEBUG) | ||
|
||
except Exception as e: | ||
xbmc.log(f'Error playing DRM stream: {str(e)}', xbmc.LOGERROR) | ||
xbmcgui.Dialog().notification('Error', 'Failed to play DRM stream', xbmcgui.NOTIFICATION_ERROR) |
Empty file.
Oops, something went wrong.